simple stuff works with --gc:stack

This commit is contained in:
Andreas Rumpf 2016-04-18 11:40:06 +02:00
commit 79f64d2469
4 changed files with 272 additions and 212 deletions

View file

@ -1291,7 +1291,7 @@ const
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"): when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
# tcc doesn't support TLS # tcc doesn't support TLS
{.error: "``--tlsEmulation:on`` must be used when using threads with tcc backend".} {.error: "``--tlsEmulation:on`` must be used when using threads with tcc backend".}
when defined(boehmgc): when defined(boehmgc):
when defined(windows): when defined(windows):
const boehmLib = "boehmgc.dll" const boehmLib = "boehmgc.dll"
@ -2565,8 +2565,9 @@ when not defined(JS): #and not defined(nimscript):
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when not defined(nimscript) and not defined(nogc): when not defined(nimscript) and not defined(nogc):
proc initGC() when not defined(gcStack):
when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc): proc initGC()
when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc) and not defined(gcStack):
proc initAllocator() {.inline.} proc initAllocator() {.inline.}
proc initStackBottom() {.inline, compilerproc.} = proc initStackBottom() {.inline, compilerproc.} =

View file

@ -36,33 +36,34 @@ type
BaseChunk = object BaseChunk = object
next: Chunk next: Chunk
size: int size: int
head, last: ptr ObjHeader # first and last object in chunk that head, tail: ptr ObjHeader # first and last object in chunk that
# has a finalizer attached to it # has a finalizer attached to it
type type
StackPtr = object StackPtr = object
chunk: pointer bump: pointer
remaining: int remaining: int
current: Chunk current: Chunk
MemRegion* = object MemRegion* = object
remaining: int remaining: int
chunk: pointer bump: pointer
head, last: Chunk head, tail: Chunk
nextChunkSize, totalSize: int nextChunkSize, totalSize: int
hole: ptr Hole # we support individual freeing hole: ptr Hole # we support individual freeing
lock: SysLock when hasThreadSupport:
lock: SysLock
var var
region {.threadVar.}: MemRegion tlRegion {.threadVar.}: MemRegion
template withRegion*(r: MemRegion; body: untyped) = template withRegion*(r: MemRegion; body: untyped) =
let oldRegion = region let oldRegion = tlRegion
region = r tlRegion = r
try: try:
body body
finally: finally:
region = oldRegion tlRegion = oldRegion
template inc(p: pointer, s: int) = template inc(p: pointer, s: int) =
p = cast[pointer](cast[int](p) +% s) p = cast[pointer](cast[int](p) +% s)
@ -71,7 +72,7 @@ template `+!`(p: pointer, s: int): pointer =
cast[pointer](cast[int](p) +% s) cast[pointer](cast[int](p) +% s)
template `-!`(p: pointer, s: int): pointer = template `-!`(p: pointer, s: int): pointer =
cast[pointer](cast[int](p) +% s) cast[pointer](cast[int](p) -% s)
proc allocSlowPath(r: var MemRegion; size: int) = proc allocSlowPath(r: var MemRegion; size: int) =
# we need to ensure that the underlying linked list # we need to ensure that the underlying linked list
@ -84,7 +85,7 @@ proc allocSlowPath(r: var MemRegion; size: int) =
r.nextChunkSize = r.nextChunkSize =
if r.totalSize < 64 * 1024: PageSize*4 if r.totalSize < 64 * 1024: PageSize*4
else: r.nextChunkSize*2 else: r.nextChunkSize*2
var s = align(size+sizeof(BaseChunk), PageSize) var s = roundup(size+sizeof(BaseChunk), PageSize)
var fresh: Chunk var fresh: Chunk
if s > r.nextChunkSize: if s > r.nextChunkSize:
fresh = cast[Chunk](osAllocPages(s)) fresh = cast[Chunk](osAllocPages(s))
@ -97,22 +98,25 @@ proc allocSlowPath(r: var MemRegion; size: int) =
else: else:
s = r.nextChunkSize s = r.nextChunkSize
fresh.size = s fresh.size = s
fresh.final = nil fresh.head = nil
r.totalSize += s fresh.tail = nil
let old = r.last inc r.totalSize, s
let old = r.tail
if old == nil: if old == nil:
r.head = fresh r.head = fresh
else: else:
r.last.next = fresh r.tail.next = fresh
r.chunk = fresh +! sizeof(BaseChunk) r.bump = fresh +! sizeof(BaseChunk)
r.last = fresh r.tail = fresh
r.remaining = s - sizeof(BaseChunk) r.remaining = s - sizeof(BaseChunk)
proc alloc(r: var MemRegion; size: int): pointer {.inline.} = proc alloc(r: var MemRegion; size: int): pointer {.inline.} =
if unlikely(r.remaining < size): allocSlowPath(r, size) if size > r.remaining:
allocSlowPath(r, size)
sysAssert(size <= r.remaining, "size <= r.remaining")
dec(r.remaining, size) dec(r.remaining, size)
result = r.chunk result = r.bump
inc r.chunk, size inc r.bump, size
proc runFinalizers(c: Chunk) = proc runFinalizers(c: Chunk) =
var it = c.head var it = c.head
@ -120,228 +124,241 @@ proc runFinalizers(c: Chunk) =
# indivually freed objects with finalizer stay in the list, but # indivually freed objects with finalizer stay in the list, but
# their typ is nil then: # their typ is nil then:
if it.typ != nil and it.typ.finalizer != nil: if it.typ != nil and it.typ.finalizer != nil:
(cast[Finalizer](cell.typ.finalizer))(cell+!sizeof(ObjHeader)) (cast[Finalizer](it.typ.finalizer))(it+!sizeof(ObjHeader))
it = it.next it = it.nextFinal
proc dealloc(r: var MemRegion; p: pointer) = proc dealloc(r: var MemRegion; p: pointer) =
let it = p-!sizeof(ObjHeader) let it = cast[ptr ObjHeader](p-!sizeof(ObjHeader))
if it.typ != nil and it.typ.finalizer != nil: if it.typ != nil and it.typ.finalizer != nil:
(cast[Finalizer](cell.typ.finalizer))(p) (cast[Finalizer](it.typ.finalizer))(p)
it.typ = nil it.typ = nil
proc deallocAll(head: Chunk) = proc deallocAll(r: var MemRegion; head: Chunk) =
var it = head var it = head
while it != nil: while it != nil:
let nxt = it.next
runFinalizers(it) runFinalizers(it)
dec r.totalSize, it.size
osDeallocPages(it, it.size) osDeallocPages(it, it.size)
it = it.next it = nxt
proc deallocAll*(r: var MemRegion) = proc deallocAll*(r: var MemRegion) =
deallocAll(r.head) deallocAll(r, r.head)
zeroMem(addr r, sizeof r) zeroMem(addr r, sizeof r)
proc obstackPtr*(r: MemRegion): StackPtr = proc obstackPtr*(r: MemRegion): StackPtr =
result.chunk = r.chunk result.bump = r.bump
result.remaining = r.remaining result.remaining = r.remaining
result.current = r.last result.current = r.tail
proc setObstackPtr*(r: MemRegion; sp: StackPtr) = template computeRemaining(r): untyped =
r.tail.size -% (cast[int](r.bump) -% cast[int](r.tail))
proc setObstackPtr*(r: var MemRegion; sp: StackPtr) =
# free everything after 'sp': # free everything after 'sp':
if sp.current != nil: if sp.current != nil:
deallocAll(sp.current.next) deallocAll(r, sp.current.next)
r.chunk = sp.chunk sp.current.next = nil
else:
deallocAll(r, r.head)
r.head = nil
r.bump = sp.bump
r.tail = sp.current
r.remaining = sp.remaining r.remaining = sp.remaining
r.last = sp.current
proc obstackPtr*(): StackPtr = tlRegion.obstackPtr()
proc setObstackPtr*(sp: StackPtr) = tlRegion.setObstackPtr(sp)
proc joinRegion*(dest: var MemRegion; src: MemRegion) = proc joinRegion*(dest: var MemRegion; src: MemRegion) =
# merging is not hard. # merging is not hard.
if dest.head.isNil: if dest.head.isNil:
dest.head = src.head dest.head = src.head
else: else:
dest.last.next = src.head dest.tail.next = src.head
dest.last = src.last dest.tail = src.tail
dest.chunk = src.chunk dest.bump = src.bump
dest.remaining = src.remaining dest.remaining = src.remaining
dest.nextChunkSize = max(dest.nextChunkSize, src.nextChunkSize) dest.nextChunkSize = max(dest.nextChunkSize, src.nextChunkSize)
dest.totalSize += src.totalSize inc dest.totalSize, src.totalSize
if dest.hole.size < src.hole.size:
dest.hole = src.hole
proc isOnHeap*(r: MemRegion; p: pointer): bool = proc isOnHeap*(r: MemRegion; p: pointer): bool =
# the last chunk is the largest, so check it first. It's also special # the tail chunk is the largest, so check it first. It's also special
# in that contains the current bump pointer: # in that contains the current bump pointer:
if r.last >= p and p < r.chunk: if r.tail >= p and p < r.bump:
return true return true
var it = r.head var it = r.head
while it != r.last: while it != r.tail:
if it >= p and p <= it+!it.size: return true if it >= p and p <= it+!it.size: return true
it = it.next it = it.next
proc isInteriorPointer(r: MemRegion; p: pointer): pointer = when false:
discard " we cannot patch stack pointers anyway!" # essential feature for later: copy data over from one region to another
type proc isInteriorPointer(r: MemRegion; p: pointer): pointer =
PointerStackChunk = object discard " we cannot patch stack pointers anyway!"
next, prev: ptr PointerStackChunk
len: int
data: array[128, pointer]
template head(s: PointerStackChunk): untyped = s.prev type
template tail(s: PointerStackChunk): untyped = s.next PointerStackChunk = object
next, prev: ptr PointerStackChunk
len: int
data: array[128, pointer]
include chains template head(s: PointerStackChunk): untyped = s.prev
template tail(s: PointerStackChunk): untyped = s.next
proc push(r: var MemRegion; s: var PointerStackChunk; x: pointer) = include chains
if s.len < high(s.data):
s.data[s.len] = x
inc s.len
else:
let fresh = cast[ptr PointerStackChunk](alloc(r, sizeof(PointerStackChunk)))
fresh.len = 1
fresh.data[0] = x
fresh.next = nil
fresh.prev = nil
append(s, fresh)
proc push(r: var MemRegion; s: var PointerStackChunk; x: pointer) =
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk; if s.len < high(s.data):
dest, src: pointer, mt: PNimType) {.benign.} s.data[s.len] = x
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk; inc s.len
dest, src: pointer, n: ptr TNimNode) {.benign.} =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
case n.kind
of nkSlot:
genericDeepCopyAux(cast[pointer](d +% n.offset),
cast[pointer](s +% n.offset), n.typ)
of nkList:
for i in 0..n.len-1:
genericDeepCopyAux(dest, src, n.sons[i])
of nkCase:
var dd = selectBranch(dest, n)
var m = selectBranch(src, n)
# reset if different branches are in use; note different branches also
# imply that's not self-assignment (``x = x``)!
if m != dd and dd != nil:
genericResetAux(dest, dd)
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ.size)
if m != nil:
genericDeepCopyAux(dest, src, m)
of nkNone: sysAssert(false, "genericDeepCopyAux")
proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} =
result = rawNewStringNoInit(dr, src.len)
result.len = src.len
c_memcpy(result.data, src.data, src.len + 1)
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
dest, src: pointer, mt: PNimType) =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
sysAssert(mt != nil, "genericDeepCopyAux 2")
case mt.kind
of tyString:
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil:
x[] = nil
else: else:
x[] = copyDeepString(cast[NimString](s2)) let fresh = cast[ptr PointerStackChunk](alloc(r, sizeof(PointerStackChunk)))
of tySequence: fresh.len = 1
var s2 = cast[PPointer](src)[] fresh.data[0] = x
var seq = cast[PGenericSeq](s2) fresh.next = nil
var x = cast[PPointer](dest) fresh.prev = nil
if s2 == nil: append(s, fresh)
x[] = nil
return
sysAssert(dest != nil, "genericDeepCopyAux 3") proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
x[] = newSeq(mt, seq.len) dest, src: pointer, mt: PNimType) {.benign.}
var dst = cast[ByteAddress](cast[PPointer](dest)[]) proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
for i in 0..seq.len-1: dest, src: pointer, n: ptr TNimNode) {.benign.} =
genericDeepCopyAux(dr, stack, var
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), d = cast[ByteAddress](dest)
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% s = cast[ByteAddress](src)
GenericSeqSize), case n.kind
mt.base) of nkSlot:
of tyObject: genericDeepCopyAux(cast[pointer](d +% n.offset),
# we need to copy m_type field for tyObject, as it could be empty for cast[pointer](s +% n.offset), n.typ)
# sequence reallocations: of nkList:
var pint = cast[ptr PNimType](dest) for i in 0..n.len-1:
pint[] = cast[ptr PNimType](src)[] genericDeepCopyAux(dest, src, n.sons[i])
if mt.base != nil: of nkCase:
genericDeepCopyAux(dr, stack, dest, src, mt.base) var dd = selectBranch(dest, n)
genericDeepCopyAux(dr, stack, dest, src, mt.node) var m = selectBranch(src, n)
of tyTuple: # reset if different branches are in use; note different branches also
genericDeepCopyAux(dr, stack, dest, src, mt.node) # imply that's not self-assignment (``x = x``)!
of tyArray, tyArrayConstr: if m != dd and dd != nil:
for i in 0..(mt.size div mt.base.size)-1: genericResetAux(dest, dd)
genericDeepCopyAux(dr, stack, copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
cast[pointer](d +% i*% mt.base.size), n.typ.size)
cast[pointer](s +% i*% mt.base.size), mt.base) if m != nil:
of tyRef: genericDeepCopyAux(dest, src, m)
let s2 = cast[PPointer](src)[] of nkNone: sysAssert(false, "genericDeepCopyAux")
if s2 == nil:
cast[PPointer](dest)[] = nil proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} =
else: result = rawNewStringNoInit(dr, src.len)
# we modify the header of the cell temporarily; instead of the type result.len = src.len
# field we store a forwarding pointer. XXX This is bad when the cloning c_memcpy(result.data, src.data, src.len + 1)
# fails due to OOM etc.
let x = usrToCell(s2) proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
let forw = cast[int](x.typ) dest, src: pointer, mt: PNimType) =
if (forw and 1) == 1: var
# we stored a forwarding pointer, so let's use that: d = cast[ByteAddress](dest)
let z = cast[pointer](forw and not 1) s = cast[ByteAddress](src)
unsureAsgnRef(cast[PPointer](dest), z) sysAssert(mt != nil, "genericDeepCopyAux 2")
case mt.kind
of tyString:
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil:
x[] = nil
else: else:
let realType = x.typ x[] = copyDeepString(cast[NimString](s2))
let z = newObj(realType, realType.base.size) of tySequence:
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[PPointer](dest)
if s2 == nil:
x[] = nil
return
sysAssert(dest != nil, "genericDeepCopyAux 3")
x[] = newSeq(mt, seq.len)
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericDeepCopyAux(dr, stack,
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
mt.base)
of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations:
var pint = cast[ptr PNimType](dest)
pint[] = cast[ptr PNimType](src)[]
if mt.base != nil:
genericDeepCopyAux(dr, stack, dest, src, mt.base)
genericDeepCopyAux(dr, stack, dest, src, mt.node)
of tyTuple:
genericDeepCopyAux(dr, stack, dest, src, mt.node)
of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1:
genericDeepCopyAux(dr, stack,
cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base)
of tyRef:
let s2 = cast[PPointer](src)[]
if s2 == nil:
cast[PPointer](dest)[] = nil
else:
# we modify the header of the cell temporarily; instead of the type
# field we store a forwarding pointer. XXX This is bad when the cloning
# fails due to OOM etc.
let x = usrToCell(s2)
let forw = cast[int](x.typ)
if (forw and 1) == 1:
# we stored a forwarding pointer, so let's use that:
let z = cast[pointer](forw and not 1)
unsureAsgnRef(cast[PPointer](dest), z)
else:
let realType = x.typ
let z = newObj(realType, realType.base.size)
unsureAsgnRef(cast[PPointer](dest), z) unsureAsgnRef(cast[PPointer](dest), z)
x.typ = cast[PNimType](cast[int](z) or 1) x.typ = cast[PNimType](cast[int](z) or 1)
genericDeepCopyAux(dr, stack, z, s2, realType.base) genericDeepCopyAux(dr, stack, z, s2, realType.base)
x.typ = realType x.typ = realType
else:
copyMem(dest, src, mt.size)
proc joinAliveDataFromRegion*(dest: var MemRegion; src: var MemRegion;
root: pointer): pointer =
# we mark the alive data and copy only alive data over to 'dest'.
# This is O(liveset) but it nicely compacts memory, so it's fine.
# We use the 'typ' field as a forwarding pointer. The forwarding
# pointers have bit 0 set, so we can disambiguate them.
# We allocate a temporary stack in 'src' that we later free:
var s: PointerStackChunk
s.len = 1
s.data[0] = root
while s.len > 0:
var p: pointer
if s.tail == nil:
p = s.data[s.len-1]
dec s.len
else: else:
p = s.tail.data[s.tail.len-1] copyMem(dest, src, mt.size)
dec s.tail.len
if s.tail.len == 0: proc joinAliveDataFromRegion*(dest: var MemRegion; src: var MemRegion;
unlink(s, s.tail) root: pointer): pointer =
# we mark the alive data and copy only alive data over to 'dest'.
# This is O(liveset) but it nicely compacts memory, so it's fine.
# We use the 'typ' field as a forwarding pointer. The forwarding
# pointers have bit 0 set, so we can disambiguate them.
# We allocate a temporary stack in 'src' that we later free:
var s: PointerStackChunk
s.len = 1
s.data[0] = root
while s.len > 0:
var p: pointer
if s.tail == nil:
p = s.data[s.len-1]
dec s.len
else:
p = s.tail.data[s.tail.len-1]
dec s.tail.len
if s.tail.len == 0:
unlink(s, s.tail)
proc rawNewObj(r: var MemRegion, typ: PNimType, size: int): pointer = proc rawNewObj(r: var MemRegion, typ: PNimType, size: int): pointer =
var res = cast[ptr ObjHeader](alloc(r, size + sizeof(ObjHeader))) var res = cast[ptr ObjHeader](alloc(r, size + sizeof(ObjHeader)))
res.typ = typ res.typ = typ
if typ.finalizer != nil: if typ.finalizer != nil:
res.nextFinal = r.chunk.head res.nextFinal = r.head.head
r.chunk.head = res r.head.head = res
result = res +! sizeof(ObjHeader) result = res +! sizeof(ObjHeader)
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
result = rawNewObj(typ, size, region) result = rawNewObj(tlRegion, typ, size)
zeroMem(result, size) zeroMem(result, size)
when defined(memProfiler): nimProfile(size) when defined(memProfiler): nimProfile(size)
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
result = rawNewObj(typ, size, region) result = rawNewObj(tlRegion, typ, size)
when defined(memProfiler): nimProfile(size) when defined(memProfiler): nimProfile(size)
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
@ -351,7 +368,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).reserved = len cast[PGenericSeq](result).reserved = len
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
result = rawNewObj(typ, size, gch) result = rawNewObj(tlRegion, typ, size)
zeroMem(result, size) zeroMem(result, size)
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
@ -360,23 +377,63 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).len = len cast[PGenericSeq](result).len = len
cast[PGenericSeq](result).reserved = len cast[PGenericSeq](result).reserved = len
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = proc growObj(region: var MemRegion; old: pointer, newsize: int): pointer =
collectCT(gch) let typ = cast[ptr ObjHeader](old -! sizeof(ObjHeader)).typ
var ol = usrToCell(old) result = rawNewObj(region, typ, newsize)
sysAssert(ol.typ != nil, "growObj: 1") let elemSize = if typ.kind == tyString: 1 else: typ.base.size
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") let oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(result, old, oldsize)
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) zeroMem(result +! oldsize, newsize-oldsize)
var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
result = cellToUsr(res)
proc growObj(old: pointer, newsize: int): pointer {.rtl.} = proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
result = growObj(old, newsize, region) result = growObj(tlRegion, old, newsize)
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
proc alloc(size: Natural): pointer =
result = cmalloc(size)
if result == nil: raiseOutOfMem()
proc alloc0(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
proc realloc(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = cfree(p)
proc allocShared(size: Natural): pointer =
result = cmalloc(size)
if result == nil: raiseOutOfMem()
proc allocShared0(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p)
when hasThreadSupport:
proc getFreeSharedMem(): int = 0
proc getTotalSharedMem(): int = 0
proc getOccupiedSharedMem(): int = 0
proc GC_disable() = discard
proc GC_enable() = discard
proc GC_fullCollect() = discard
proc GC_setStrategy(strategy: GC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
proc getOccupiedMem(): int =
result = tlRegion.totalSize - tlRegion.remaining
proc getFreeMem(): int = tlRegion.remaining
proc getTotalMem(): int =
result = tlRegion.totalSize
proc setStackBottom(theStackBottom: pointer) = discard

View file

@ -511,11 +511,12 @@ elif defined(nogc):
include "system/cellsets" include "system/cellsets"
else: else:
include "system/alloc" when not defined(gcStack):
include "system/alloc"
include "system/cellsets" include "system/cellsets"
when not leakDetector and not useCellIds: when not leakDetector and not useCellIds:
sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell") sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell")
when compileOption("gc", "v2"): when compileOption("gc", "v2"):
include "system/gc2" include "system/gc2"
elif defined(gcStack): elif defined(gcStack):

View file

@ -228,7 +228,8 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
elif newLen < result.len: elif newLen < result.len:
# we need to decref here, otherwise the GC leaks! # we need to decref here, otherwise the GC leaks!
when not defined(boehmGC) and not defined(nogc) and when not defined(boehmGC) and not defined(nogc) and
not defined(gcMarkAndSweep) and not defined(gogc): not defined(gcMarkAndSweep) and not defined(gogc) and
not defined(gcStack):
when false: # compileOption("gc", "v2"): when false: # compileOption("gc", "v2"):
for i in newLen..result.len-1: for i in newLen..result.len-1:
let len0 = gch.tempStack.len let len0 = gch.tempStack.len