lib/system/a-e - Dropped 'T' from types

This commit is contained in:
pdw 2015-05-24 22:37:01 -05:00 • committed by Araq
commit ff5b446dfc
11 changed files with 270 additions and 252 deletions

View file

@ -249,7 +249,7 @@ when defined(nimNewShared):
guarded* {.magic: "Guarded".} guarded* {.magic: "Guarded".}
# comparison operators: # comparison operators:
proc `==` *[TEnum: enum](x, y: TEnum): bool {.magic: "EqEnum", noSideEffect.} proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.}
proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.}
proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.} proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.}
proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.} proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.}
@ -260,7 +260,7 @@ proc `==` *[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.}
proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.}
proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.}
proc `<=` *[TEnum: enum](x, y: TEnum): bool {.magic: "LeEnum", noSideEffect.} proc `<=` *[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.}
proc `<=` *(x, y: string): bool {.magic: "LeStr", noSideEffect.} proc `<=` *(x, y: string): bool {.magic: "LeStr", noSideEffect.}
proc `<=` *(x, y: char): bool {.magic: "LeCh", noSideEffect.} proc `<=` *(x, y: char): bool {.magic: "LeCh", noSideEffect.}
proc `<=` *[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} proc `<=` *[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.}
@ -268,7 +268,7 @@ proc `<=` *(x, y: bool): bool {.magic: "LeB", noSideEffect.}
proc `<=` *[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.} proc `<=` *[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.}
proc `<=` *(x, y: pointer): bool {.magic: "LePtr", noSideEffect.} proc `<=` *(x, y: pointer): bool {.magic: "LePtr", noSideEffect.}
proc `<` *[TEnum: enum](x, y: TEnum): bool {.magic: "LtEnum", noSideEffect.} proc `<` *[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.}
proc `<` *(x, y: string): bool {.magic: "LtStr", noSideEffect.} proc `<` *(x, y: string): bool {.magic: "LtStr", noSideEffect.}
proc `<` *(x, y: char): bool {.magic: "LtCh", noSideEffect.} proc `<` *(x, y: char): bool {.magic: "LtCh", noSideEffect.}
proc `<` *[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} proc `<` *[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.}
@ -332,7 +332,7 @@ type
RootObj* {.exportc: "TNimObject", inheritable.} = RootObj* {.exportc: "TNimObject", inheritable.} =
object ## the root of Nim's object hierarchy. Objects should object ## the root of Nim's object hierarchy. Objects should
## inherit from TObject or one of its descendants. However, ## inherit from RootObj or one of its descendants. However,
## objects that have no ancestor are allowed. ## objects that have no ancestor are allowed.
RootRef* = ref RootObj ## reference to RootObj RootRef* = ref RootObj ## reference to RootObj
@ -1505,7 +1505,7 @@ proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
## as it is. This operator is useful for generic code, so ## as it is. This operator is useful for generic code, so
## that ``$expr`` also works if ``expr`` is already a string. ## that ``$expr`` also works if ``expr`` is already a string.
proc `$` *[TEnum: enum](x: TEnum): string {.magic: "EnumToStr", noSideEffect.} proc `$` *[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
## The stringify operator for an enumeration argument. This works for ## The stringify operator for an enumeration argument. This works for
## any enumeration type thanks to compiler magic. If ## any enumeration type thanks to compiler magic. If
## a ``$`` operator for a concrete enumeration is provided, this is ## a ``$`` operator for a concrete enumeration is provided, this is
@ -2213,6 +2213,7 @@ type
filename*: cstring ## filename of the proc that is currently executing filename*: cstring ## filename of the proc that is currently executing
len*: int16 ## length of the inspectable slots len*: int16 ## length of the inspectable slots
calldepth*: int16 ## used for max call depth checking calldepth*: int16 ## used for max call depth checking
#{.deprecated: [TFrame: Frame].}
when defined(JS): when defined(JS):
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
@ -2414,7 +2415,7 @@ when not defined(JS): #and not defined(NimrodVM):
proc open*(f: var File, filehandle: FileHandle, proc open*(f: var File, filehandle: FileHandle,
mode: FileMode = fmRead): bool {.tags: [], benign.} mode: FileMode = fmRead): bool {.tags: [], benign.}
## Creates a ``TFile`` from a `filehandle` with given `mode`. ## Creates a ``File`` from a `filehandle` with given `mode`.
## ##
## Default mode is readonly. Returns true iff the file could be opened. ## Default mode is readonly. Returns true iff the file could be opened.
@ -2604,6 +2605,8 @@ when not defined(JS): #and not defined(NimrodVM):
context: C_JmpBuf context: C_JmpBuf
hasRaiseAction: bool hasRaiseAction: bool
raiseAction: proc (e: ref Exception): bool {.closure.} raiseAction: proc (e: ref Exception): bool {.closure.}
SafePoint = TSafePoint
# {.deprecated: [TSafePoint: SafePoint].}
when declared(initAllocator): when declared(initAllocator):
initAllocator() initAllocator()
@ -3054,9 +3057,10 @@ proc raiseAssert*(msg: string) {.noinline.} =
proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
# trick the compiler to not list ``AssertionError`` when called # trick the compiler to not list ``AssertionError`` when called
# by ``assert``. # by ``assert``.
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect, type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect,
tags: [].} tags: [].}
THide(raiseAssert)(msg) {.deprecated: [THide: Hide].}
Hide(raiseAssert)(msg)
template assert*(cond: bool, msg = "") = template assert*(cond: bool, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note ## Raises ``AssertionError`` with `msg` if `cond` is false. Note

View file

@ -98,46 +98,49 @@ const
SmallChunkSize = PageSize SmallChunkSize = PageSize
type type
PTrunk = ptr TTrunk PTrunk = ptr Trunk
TTrunk {.final.} = object Trunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0 key: int # start address at bit 0
bits: array[0..IntsPerTrunk-1, int] # a bit vector bits: array[0..IntsPerTrunk-1, int] # a bit vector
TTrunkBuckets = array[0..255, PTrunk] TrunkBuckets = array[0..255, PTrunk]
TIntSet {.final.} = object IntSet {.final.} = object
data: TTrunkBuckets data: TrunkBuckets
{.deprecated: [TIntSet: IntSet, TTrunk: Trunk, TTrunkBuckets: TrunkBuckets].}
type type
TAlignType = BiggestFloat AlignType = BiggestFloat
TFreeCell {.final, pure.} = object FreeCell {.final, pure.} = object
next: ptr TFreeCell # next free cell in chunk (overlaid with refcount) next: ptr FreeCell # next free cell in chunk (overlaid with refcount)
zeroField: int # 0 means cell is not used (overlaid with typ field) zeroField: int # 0 means cell is not used (overlaid with typ field)
# 1 means cell is manually managed pointer # 1 means cell is manually managed pointer
# otherwise a PNimType is stored in there # otherwise a PNimType is stored in there
PChunk = ptr TBaseChunk PChunk = ptr BaseChunk
PBigChunk = ptr TBigChunk PBigChunk = ptr BigChunk
PSmallChunk = ptr TSmallChunk PSmallChunk = ptr SmallChunk
TBaseChunk {.pure, inheritable.} = object BaseChunk {.pure, inheritable.} = object
prevSize: int # size of previous chunk; for coalescing prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize... used: bool # later will be optimized into prevSize...
TSmallChunk = object of TBaseChunk SmallChunk = object of BaseChunk
next, prev: PSmallChunk # chunks of the same size next, prev: PSmallChunk # chunks of the same size
freeList: ptr TFreeCell freeList: ptr FreeCell
free: int # how many bytes remain free: int # how many bytes remain
acc: int # accumulator for small object allocation acc: int # accumulator for small object allocation
data: TAlignType # start of usable memory data: AlignType # start of usable memory
TBigChunk = object of TBaseChunk # not necessarily > PageSize! BigChunk = object of BaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size next, prev: PBigChunk # chunks of the same (or bigger) size
align: int align: int
data: TAlignType # start of usable memory data: AlignType # start of usable memory
{.deprecated: [TAlignType: AlignType, TFreeCell: FreeCell, TBaseChunk: BaseChunk,
TBigChunk: BigChunk, TSmallChunk: SmallChunk].}
template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType) template smallChunkOverhead(): expr = sizeof(SmallChunk)-sizeof(AlignType)
template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType) template bigChunkOverhead(): expr = sizeof(BigChunk)-sizeof(AlignType)
proc roundup(x, v: int): int {.inline.} = proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1) result = (x + (v-1)) and not (v-1)
@ -156,31 +159,32 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
# to the OS), a fixed size array can be used. # to the OS), a fixed size array can be used.
type type
PLLChunk = ptr TLLChunk PLLChunk = ptr LLChunk
TLLChunk {.pure.} = object ## *low-level* chunk LLChunk {.pure.} = object ## *low-level* chunk
size: int # remaining size size: int # remaining size
acc: int # accumulator acc: int # accumulator
next: PLLChunk # next low-level chunk; only needed for dealloc next: PLLChunk # next low-level chunk; only needed for dealloc
PAvlNode = ptr TAvlNode PAvlNode = ptr AvlNode
TAvlNode {.pure, final.} = object AvlNode {.pure, final.} = object
link: array[0..1, PAvlNode] # Left (0) and right (1) links link: array[0..1, PAvlNode] # Left (0) and right (1) links
key, upperBound: int key, upperBound: int
level: int level: int
TMemRegion {.final, pure.} = object MemRegion {.final, pure.} = object
minLargeObj, maxLargeObj: int minLargeObj, maxLargeObj: int
freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk] freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
llmem: PLLChunk llmem: PLLChunk
currMem, maxMem, freeMem: int # memory sizes (allocated from OS) currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
lastSize: int # needed for the case that OS gives us pages linearly lastSize: int # needed for the case that OS gives us pages linearly
freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
chunkStarts: TIntSet chunkStarts: IntSet
root, deleted, last, freeAvlNodes: PAvlNode root, deleted, last, freeAvlNodes: PAvlNode
{.deprecated: [TLLChunk: LLChunk, TAvlNode: AvlNode, TMemRegion: MemRegion].}
# shared: # shared:
var var
bottomData: TAvlNode bottomData: AvlNode
bottom: PAvlNode bottom: PAvlNode
{.push stack_trace: off.} {.push stack_trace: off.}
@ -191,44 +195,44 @@ proc initAllocator() =
bottom.link[1] = bottom bottom.link[1] = bottom
{.pop.} {.pop.}
proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} = proc incCurrMem(a: var MemRegion, bytes: int) {.inline.} =
inc(a.currMem, bytes) inc(a.currMem, bytes)
proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} = proc decCurrMem(a: var MemRegion, bytes: int) {.inline.} =
a.maxMem = max(a.maxMem, a.currMem) a.maxMem = max(a.maxMem, a.currMem)
dec(a.currMem, bytes) dec(a.currMem, bytes)
proc getMaxMem(a: var TMemRegion): int = proc getMaxMem(a: var MemRegion): int =
# Since we update maxPagesCount only when freeing pages, # Since we update maxPagesCount only when freeing pages,
# maxPagesCount may not be up to date. Thus we use the # maxPagesCount may not be up to date. Thus we use the
# maximum of these both values here: # maximum of these both values here:
result = max(a.currMem, a.maxMem) result = max(a.currMem, a.maxMem)
proc llAlloc(a: var TMemRegion, size: int): pointer = proc llAlloc(a: var MemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation # *low-level* alloc for the memory managers data structures. Deallocation
# is done at he end of the allocator's life time. # is done at he end of the allocator's life time.
if a.llmem == nil or size > a.llmem.size: if a.llmem == nil or size > a.llmem.size:
# the requested size is ``roundup(size+sizeof(TLLChunk), PageSize)``, but # the requested size is ``roundup(size+sizeof(LLChunk), PageSize)``, but
# since we know ``size`` is a (small) constant, we know the requested size # since we know ``size`` is a (small) constant, we know the requested size
# is one page: # is one page:
sysAssert roundup(size+sizeof(TLLChunk), PageSize) == PageSize, "roundup 6" sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
var old = a.llmem # can be nil and is correct with nil var old = a.llmem # can be nil and is correct with nil
a.llmem = cast[PLLChunk](osAllocPages(PageSize)) a.llmem = cast[PLLChunk](osAllocPages(PageSize))
incCurrMem(a, PageSize) incCurrMem(a, PageSize)
a.llmem.size = PageSize - sizeof(TLLChunk) a.llmem.size = PageSize - sizeof(LLChunk)
a.llmem.acc = sizeof(TLLChunk) a.llmem.acc = sizeof(LLChunk)
a.llmem.next = old a.llmem.next = old
result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc) result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc)
dec(a.llmem.size, size) dec(a.llmem.size, size)
inc(a.llmem.acc, size) inc(a.llmem.acc, size)
zeroMem(result, size) zeroMem(result, size)
proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode = proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
if a.freeAvlNodes != nil: if a.freeAvlNodes != nil:
result = a.freeAvlNodes result = a.freeAvlNodes
a.freeAvlNodes = a.freeAvlNodes.link[0] a.freeAvlNodes = a.freeAvlNodes.link[0]
else: else:
result = cast[PAvlNode](llAlloc(a, sizeof(TAvlNode))) result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode)))
result.key = key result.key = key
result.upperBound = upperBound result.upperBound = upperBound
result.link[0] = bottom result.link[0] = bottom
@ -238,13 +242,13 @@ proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode =
sysAssert(bottom.link[0] == bottom, "bottom link[0]") sysAssert(bottom.link[0] == bottom, "bottom link[0]")
sysAssert(bottom.link[1] == bottom, "bottom link[1]") sysAssert(bottom.link[1] == bottom, "bottom link[1]")
proc deallocAvlNode(a: var TMemRegion, n: PAvlNode) {.inline.} = proc deallocAvlNode(a: var MemRegion, n: PAvlNode) {.inline.} =
n.link[0] = a.freeAvlNodes n.link[0] = a.freeAvlNodes
a.freeAvlNodes = n a.freeAvlNodes = n
include "system/avltree" include "system/avltree"
proc llDeallocAll(a: var TMemRegion) = proc llDeallocAll(a: var MemRegion) =
var it = a.llmem var it = a.llmem
while it != nil: while it != nil:
# we know each block in the list has the size of 1 page: # we know each block in the list has the size of 1 page:
@ -252,14 +256,14 @@ proc llDeallocAll(a: var TMemRegion) =
osDeallocPages(it, PageSize) osDeallocPages(it, PageSize)
it = next it = next
proc intSetGet(t: TIntSet, key: int): PTrunk = proc intSetGet(t: IntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)] var it = t.data[key and high(t.data)]
while it != nil: while it != nil:
if it.key == key: return it if it.key == key: return it
it = it.next it = it.next
result = nil result = nil
proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk = proc intSetPut(a: var MemRegion, t: var IntSet, key: int): PTrunk =
result = intSetGet(t, key) result = intSetGet(t, key)
if result == nil: if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[]))) result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@ -267,7 +271,7 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
t.data[key and high(t.data)] = result t.data[key and high(t.data)] = result
result.key = key result.key = key
proc contains(s: TIntSet, key: int): bool = proc contains(s: IntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift) var t = intSetGet(s, key shr TrunkShift)
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
@ -275,19 +279,19 @@ proc contains(s: TIntSet, key: int): bool =
else: else:
result = false result = false
proc incl(a: var TMemRegion, s: var TIntSet, key: int) = proc incl(a: var MemRegion, s: var IntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift) var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask)) t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TIntSet, key: int) = proc excl(s: var IntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift) var t = intSetGet(s, key shr TrunkShift)
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] and not t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
(1 shl (u and IntMask)) (1 shl (u and IntMask))
iterator elements(t: TIntSet): int {.inline.} = iterator elements(t: IntSet): int {.inline.} =
# while traversing it is forbidden to change the set! # while traversing it is forbidden to change the set!
for h in 0..high(t.data): for h in 0..high(t.data):
var r = t.data[h] var r = t.data[h]
@ -311,7 +315,7 @@ proc isSmallChunk(c: PChunk): bool {.inline.} =
proc chunkUnused(c: PChunk): bool {.inline.} = proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} = iterator allObjects(m: MemRegion): pointer {.inline.} =
for s in elements(m.chunkStarts): for s in elements(m.chunkStarts):
# we need to check here again as it could have been modified: # we need to check here again as it could have been modified:
if s in m.chunkStarts: if s in m.chunkStarts:
@ -331,7 +335,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
yield addr(c.data) yield addr(c.data)
proc isCell(p: pointer): bool {.inline.} = proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1 result = cast[ptr FreeCell](p).zeroField >% 1
# ------------- chunk management ---------------------------------------------- # ------------- chunk management ----------------------------------------------
proc pageIndex(c: PChunk): int {.inline.} = proc pageIndex(c: PChunk): int {.inline.} =
@ -344,7 +348,7 @@ proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask) result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result))) #sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
incCurrMem(a, size) incCurrMem(a, size)
inc(a.freeMem, size) inc(a.freeMem, size)
result = cast[PBigChunk](osAllocPages(size)) result = cast[PBigChunk](osAllocPages(size))
@ -373,7 +377,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
result.prevSize = 0 # unknown result.prevSize = 0 # unknown
a.lastSize = size # for next request a.lastSize = size # for next request
proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) = proc freeOsChunks(a: var MemRegion, p: pointer, size: int) =
# update next.prevSize: # update next.prevSize:
var c = cast[PChunk](p) var c = cast[PChunk](p)
var nxt = cast[ByteAddress](p) +% c.size var nxt = cast[ByteAddress](p) +% c.size
@ -387,7 +391,7 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
dec(a.freeMem, size) dec(a.freeMem, size)
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size) #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} = proc isAccessible(a: MemRegion, p: pointer): bool {.inline.} =
result = contains(a.chunkStarts, pageIndex(p)) result = contains(a.chunkStarts, pageIndex(p))
proc contains[T](list, x: T): bool = proc contains[T](list, x: T): bool =
@ -396,7 +400,7 @@ proc contains[T](list, x: T): bool =
if it == x: return true if it == x: return true
it = it.next it = it.next
proc writeFreeList(a: TMemRegion) = proc writeFreeList(a: MemRegion) =
var it = a.freeChunksList var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it) c_fprintf(c_stdout, "freeChunksList: %p\n", it)
while it != nil: while it != nil:
@ -427,14 +431,14 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
c.next = nil c.next = nil
c.prev = nil c.prev = nil
proc updatePrevSize(a: var TMemRegion, c: PBigChunk, proc updatePrevSize(a: var MemRegion, c: PBigChunk,
prevSize: int) {.inline.} = prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize") sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
if isAccessible(a, ri): if isAccessible(a, ri):
ri.prevSize = prevSize ri.prevSize = prevSize
proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
var c = c var c = c
sysAssert(c.size >= PageSize, "freeBigChunk") sysAssert(c.size >= PageSize, "freeBigChunk")
inc(a.freeMem, c.size) inc(a.freeMem, c.size)
@ -467,7 +471,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
else: else:
freeOsChunks(a, c, c.size) freeOsChunks(a, c, c.size)
proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) = proc splitChunk(a: var MemRegion, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[ByteAddress](c) +% size) var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
sysAssert(rest notin a.freeChunksList, "splitChunk") sysAssert(rest notin a.freeChunksList, "splitChunk")
rest.size = c.size - size rest.size = c.size - size
@ -480,7 +484,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
incl(a, a.chunkStarts, pageIndex(rest)) incl(a, a.chunkStarts, pageIndex(rest))
listAdd(a.freeChunksList, rest) listAdd(a.freeChunksList, rest)
proc getBigChunk(a: var TMemRegion, size: int): PBigChunk = proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
# use first fit for now: # use first fit for now:
sysAssert((size and PageMask) == 0, "getBigChunk 1") sysAssert((size and PageMask) == 0, "getBigChunk 1")
sysAssert(size > 0, "getBigChunk 2") sysAssert(size > 0, "getBigChunk 2")
@ -507,16 +511,16 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
incl(a, a.chunkStarts, pageIndex(result)) incl(a, a.chunkStarts, pageIndex(result))
dec(a.freeMem, size) dec(a.freeMem, size)
proc getSmallChunk(a: var TMemRegion): PSmallChunk = proc getSmallChunk(a: var MemRegion): PSmallChunk =
var res = getBigChunk(a, PageSize) var res = getBigChunk(a, PageSize)
sysAssert res.prev == nil, "getSmallChunk 1" sysAssert res.prev == nil, "getSmallChunk 1"
sysAssert res.next == nil, "getSmallChunk 2" sysAssert res.next == nil, "getSmallChunk 2"
result = cast[PSmallChunk](res) result = cast[PSmallChunk](res)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool {.benign.} proc isAllocatedPtr(a: MemRegion, p: pointer): bool {.benign.}
proc allocInv(a: TMemRegion): bool = proc allocInv(a: MemRegion): bool =
## checks some (not all yet) invariants of the allocator's data structures. ## checks some (not all yet) invariants of the allocator's data structures.
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks): for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s] var c = a.freeSmallChunks[s]
@ -537,10 +541,10 @@ proc allocInv(a: TMemRegion): bool =
c = c.next c = c.next
result = true result = true
proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: begin") sysAssert(allocInv(a), "rawAlloc: begin")
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small") sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small")
var size = roundup(requestedSize, MemAlign) var size = roundup(requestedSize, MemAlign)
sysAssert(size >= requestedSize, "insufficient allocated size!") sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size) #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
@ -601,11 +605,11 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: end") sysAssert(allocInv(a), "rawAlloc: end")
when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result) when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer = proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
result = rawAlloc(a, requestedSize) result = rawAlloc(a, requestedSize)
zeroMem(result, requestedSize) zeroMem(result, requestedSize)
proc rawDealloc(a: var TMemRegion, p: pointer) = proc rawDealloc(a: var MemRegion, p: pointer) =
#sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer") #sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
sysAssert(allocInv(a), "rawDealloc: begin") sysAssert(allocInv(a), "rawDealloc: begin")
var c = pageAddr(p) var c = pageAddr(p)
@ -615,7 +619,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
var s = c.size var s = c.size
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
s == 0, "rawDealloc 3") s == 0, "rawDealloc 3")
var f = cast[ptr TFreeCell](p) var f = cast[ptr FreeCell](p)
#echo("setting to nil: ", $cast[TAddress](addr(f.zeroField))) #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField)))
sysAssert(f.zeroField != 0, "rawDealloc 1") sysAssert(f.zeroField != 0, "rawDealloc 1")
f.zeroField = 0 f.zeroField = 0
@ -623,8 +627,8 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
c.freeList = f c.freeList = f
when overwriteFree: when overwriteFree:
# set to 0xff to check for usage after free bugs: # set to 0xff to check for usage after free bugs:
c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32, c_memset(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32,
s -% sizeof(TFreeCell)) s -% sizeof(FreeCell))
# check if it is not in the freeSmallChunks[s] list: # check if it is not in the freeSmallChunks[s] list:
if c.free < s: if c.free < s:
# add it to the freeSmallChunks[s] array: # add it to the freeSmallChunks[s] array:
@ -649,7 +653,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: end") sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p) when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = proc isAllocatedPtr(a: MemRegion, p: pointer): bool =
if isAccessible(a, p): if isAccessible(a, p):
var c = pageAddr(p) var c = pageAddr(p)
if not chunkUnused(c): if not chunkUnused(c):
@ -658,16 +662,16 @@ proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
var offset = (cast[ByteAddress](p) and (PageSize-1)) -% var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead() smallChunkOverhead()
result = (c.acc >% offset) and (offset %% c.size == 0) and result = (c.acc >% offset) and (offset %% c.size == 0) and
(cast[ptr TFreeCell](p).zeroField >% 1) (cast[ptr FreeCell](p).zeroField >% 1)
else: else:
var c = cast[PBigChunk](c) var c = cast[PBigChunk](c)
result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1 result = p == addr(c.data) and cast[ptr FreeCell](p).zeroField >% 1
proc prepareForInteriorPointerChecking(a: var TMemRegion) {.inline.} = proc prepareForInteriorPointerChecking(a: var MemRegion) {.inline.} =
a.minLargeObj = lowGauge(a.root) a.minLargeObj = lowGauge(a.root)
a.maxLargeObj = highGauge(a.root) a.maxLargeObj = highGauge(a.root)
proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer = proc interiorAllocatedPtr(a: MemRegion, p: pointer): pointer =
if isAccessible(a, p): if isAccessible(a, p):
var c = pageAddr(p) var c = pageAddr(p)
if not chunkUnused(c): if not chunkUnused(c):
@ -678,7 +682,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
if c.acc >% offset: if c.acc >% offset:
sysAssert(cast[ByteAddress](addr(c.data)) +% offset == sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
cast[ByteAddress](p), "offset is not what you think it is") cast[ByteAddress](p), "offset is not what you think it is")
var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +% var d = cast[ptr FreeCell](cast[ByteAddress](addr(c.data)) +%
offset -% (offset %% c.size)) offset -% (offset %% c.size))
if d.zeroField >% 1: if d.zeroField >% 1:
result = d result = d
@ -686,7 +690,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
else: else:
var c = cast[PBigChunk](c) var c = cast[PBigChunk](c)
var d = addr(c.data) var d = addr(c.data)
if p >= d and cast[ptr TFreeCell](d).zeroField >% 1: if p >= d and cast[ptr FreeCell](d).zeroField >% 1:
result = d result = d
sysAssert isAllocatedPtr(a, result), " result wrong pointer!" sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
else: else:
@ -699,38 +703,38 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
var k = cast[pointer](avlNode.key) var k = cast[pointer](avlNode.key)
var c = cast[PBigChunk](pageAddr(k)) var c = cast[PBigChunk](pageAddr(k))
sysAssert(addr(c.data) == k, " k is not the same as addr(c.data)!") sysAssert(addr(c.data) == k, " k is not the same as addr(c.data)!")
if cast[ptr TFreeCell](k).zeroField >% 1: if cast[ptr FreeCell](k).zeroField >% 1:
result = k result = k
sysAssert isAllocatedPtr(a, result), " result wrong pointer!" sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
proc ptrSize(p: pointer): int = proc ptrSize(p: pointer): int =
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell)) var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell))
var c = pageAddr(p) var c = pageAddr(p)
sysAssert(not chunkUnused(c), "ptrSize") sysAssert(not chunkUnused(c), "ptrSize")
result = c.size -% sizeof(TFreeCell) result = c.size -% sizeof(FreeCell)
if not isSmallChunk(c): if not isSmallChunk(c):
dec result, bigChunkOverhead() dec result, bigChunkOverhead()
proc alloc(allocator: var TMemRegion, size: Natural): pointer = proc alloc(allocator: var MemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(TFreeCell)) result = rawAlloc(allocator, size+sizeof(FreeCell))
cast[ptr TFreeCell](result).zeroField = 1 # mark it as used cast[ptr FreeCell](result).zeroField = 1 # mark it as used
sysAssert(not isAllocatedPtr(allocator, result), "alloc") sysAssert(not isAllocatedPtr(allocator, result), "alloc")
result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell)) result = cast[pointer](cast[ByteAddress](result) +% sizeof(FreeCell))
proc alloc0(allocator: var TMemRegion, size: Natural): pointer = proc alloc0(allocator: var MemRegion, size: Natural): pointer =
result = alloc(allocator, size) result = alloc(allocator, size)
zeroMem(result, size) zeroMem(result, size)
proc dealloc(allocator: var TMemRegion, p: pointer) = proc dealloc(allocator: var MemRegion, p: pointer) =
sysAssert(p != nil, "dealloc 0") sysAssert(p != nil, "dealloc 0")
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell)) var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell))
sysAssert(x != nil, "dealloc 1") sysAssert(x != nil, "dealloc 1")
sysAssert(isAccessible(allocator, x), "is not accessible") sysAssert(isAccessible(allocator, x), "is not accessible")
sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 2") sysAssert(cast[ptr FreeCell](x).zeroField == 1, "dealloc 2")
rawDealloc(allocator, x) rawDealloc(allocator, x)
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3") sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
proc realloc(allocator: var TMemRegion, 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 = alloc0(allocator, newsize)
if p != nil: if p != nil:
@ -739,7 +743,7 @@ proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
elif p != nil: elif p != nil:
dealloc(allocator, p) dealloc(allocator, p)
proc deallocOsPages(a: var TMemRegion) = 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:
for p in elements(a.chunkStarts): for p in elements(a.chunkStarts):
var page = cast[PChunk](p shl PageShift) var page = cast[PChunk](p shl PageShift)
@ -756,9 +760,9 @@ proc deallocOsPages(a: var TMemRegion) =
# And then we free the pages that are in use for the page bits: # And then we free the pages that are in use for the page bits:
llDeallocAll(a) llDeallocAll(a)
proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem proc getFreeMem(a: MemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem proc getTotalMem(a: MemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: TMemRegion): int {.inline.} = proc getOccupiedMem(a: MemRegion): int {.inline.} =
result = a.currMem - a.freeMem result = a.currMem - a.freeMem
# ---------------------- thread memory region ------------------------------- # ---------------------- thread memory region -------------------------------
@ -769,7 +773,7 @@ template instantiateForRegion(allocator: expr) =
result = interiorAllocatedPtr(allocator, p) result = interiorAllocatedPtr(allocator, p)
proc isAllocatedPtr*(p: pointer): bool = proc isAllocatedPtr*(p: pointer): bool =
let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(TCell))) let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(Cell)))
result = isAllocatedPtr(allocator, p) result = isAllocatedPtr(allocator, p)
proc deallocOsPages = deallocOsPages(allocator) proc deallocOsPages = deallocOsPages(allocator)
@ -803,8 +807,8 @@ template instantiateForRegion(allocator: expr) =
# -------------------- shared heap region ---------------------------------- # -------------------- shared heap region ----------------------------------
when hasThreadSupport: when hasThreadSupport:
var sharedHeap: TMemRegion var sharedHeap: MemRegion
var heapLock: TSysLock var heapLock: SysLock
initSysLock(heapLock) initSysLock(heapLock)
proc allocShared(size: Natural): pointer = proc allocShared(size: Natural): pointer =

View file

@ -37,39 +37,40 @@ when someGcc and hasThreadSupport:
## and release stores in all threads. ## and release stores in all threads.
type type
TAtomType* = SomeNumber|pointer|ptr|char|bool AtomType* = SomeNumber|pointer|ptr|char|bool
## Type Class representing valid types for use with atomic procs ## Type Class representing valid types for use with atomic procs
{.deprecated: [TAtomType: AtomType].}
proc atomicLoadN*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {. proc atomicLoadN*[T: AtomType](p: ptr T, mem: AtomMemModel): T {.
importc: "__atomic_load_n", nodecl.} importc: "__atomic_load_n", nodecl.}
## This proc implements an atomic load operation. It returns the contents at p. ## This proc implements an atomic load operation. It returns the contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME. ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {. proc atomicLoad*[T: AtomType](p, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_load", nodecl.} importc: "__atomic_load", nodecl.}
## This is the generic version of an atomic load. It returns the contents at p in ret. ## This is the generic version of an atomic load. It returns the contents at p in ret.
proc atomicStoreN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {. proc atomicStoreN*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel) {.
importc: "__atomic_store_n", nodecl.} importc: "__atomic_store_n", nodecl.}
## This proc implements an atomic store operation. It writes val at p. ## This proc implements an atomic store operation. It writes val at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE. ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
proc atomicStore*[T: TAtomType](p, val: ptr T, mem: AtomMemModel) {. proc atomicStore*[T: AtomType](p, val: ptr T, mem: AtomMemModel) {.
importc: "__atomic_store", nodecl.} importc: "__atomic_store", nodecl.}
## This is the generic version of an atomic store. It stores the value of val at p ## This is the generic version of an atomic store. It stores the value of val at p
proc atomicExchangeN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicExchangeN*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_exchange_n", nodecl.} importc: "__atomic_exchange_n", nodecl.}
## This proc implements an atomic exchange operation. It writes val at p, ## This proc implements an atomic exchange operation. It writes val at p,
## and returns the previous contents at p. ## and returns the previous contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {. proc atomicExchange*[T: AtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_exchange", nodecl.} importc: "__atomic_exchange", nodecl.}
## This is the generic version of an atomic exchange. It stores the contents at val at p. ## This is the generic version of an atomic exchange. It stores the contents at val at p.
## The original value at p is copied into ret. ## The original value at p is copied into ret.
proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T, proc atomicCompareExchangeN*[T: AtomType](p, expected: ptr T, desired: T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {. weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.} importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements an atomic compare and exchange operation. This compares the ## This proc implements an atomic compare and exchange operation. This compares the
@ -85,7 +86,7 @@ when someGcc and hasThreadSupport:
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model ## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel. ## than that specified by success_memmodel.
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T, proc atomicCompareExchange*[T: AtomType](p, expected, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {. weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange", nodecl.} importc: "__atomic_compare_exchange", nodecl.}
## This proc implements the generic version of atomic_compare_exchange. ## This proc implements the generic version of atomic_compare_exchange.
@ -93,31 +94,31 @@ when someGcc and hasThreadSupport:
## value is also a pointer. ## value is also a pointer.
## Perform the operation return the new value, all memory models are valid ## Perform the operation return the new value, all memory models are valid
proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicAddFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.} importc: "__atomic_add_fetch", nodecl.}
proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicSubFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.} importc: "__atomic_sub_fetch", nodecl.}
proc atomicOrFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicOrFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.} importc: "__atomic_or_fetch ", nodecl.}
proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicAndFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.} importc: "__atomic_and_fetch", nodecl.}
proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicXorFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.} importc: "__atomic_xor_fetch", nodecl.}
proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicNandFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_nand_fetch ", nodecl.} importc: "__atomic_nand_fetch ", nodecl.}
## Perform the operation return the old value, all memory models are valid ## Perform the operation return the old value, all memory models are valid
proc atomicFetchAdd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicFetchAdd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add", nodecl.} importc: "__atomic_fetch_add", nodecl.}
proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicFetchSub*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub", nodecl.} importc: "__atomic_fetch_sub", nodecl.}
proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicFetchOr*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or", nodecl.} importc: "__atomic_fetch_or", nodecl.}
proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicFetchAnd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and", nodecl.} importc: "__atomic_fetch_and", nodecl.}
proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicFetchXor*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor", nodecl.} importc: "__atomic_fetch_xor", nodecl.}
proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {. proc atomicFetchNand*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_nand", nodecl.} importc: "__atomic_fetch_nand", nodecl.}
proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {. proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.

View file

@ -51,7 +51,7 @@ proc split(t: var PAvlNode) =
t.link[0] = temp t.link[0] = temp
inc t.level inc t.level
proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} = proc add(a: var MemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
if t == bottom: if t == bottom:
t = allocAvlNode(a, key, upperBound) t = allocAvlNode(a, key, upperBound)
else: else:
@ -64,7 +64,7 @@ proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
skew(t) skew(t)
split(t) split(t)
proc del(a: var TMemRegion, t: var PAvlNode, x: int) {.benign.} = proc del(a: var MemRegion, t: var PAvlNode, x: int) {.benign.} =
if t == bottom: return if t == bottom: return
a.last = t a.last = t
if x <% t.key: if x <% t.key:

View file

@ -10,10 +10,10 @@
# Efficient set of pointers for the GC (and repr) # Efficient set of pointers for the GC (and repr)
type type
TRefCount = int RefCount = int
TCell {.pure.} = object Cell {.pure.} = object
refcount: TRefCount # the refcount and some flags refcount: RefCount # the refcount and some flags
typ: PNimType typ: PNimType
when trackAllocationSource: when trackAllocationSource:
filename: cstring filename: cstring
@ -21,34 +21,35 @@ type
when useCellIds: when useCellIds:
id: int id: int
PCell = ptr TCell PCell = ptr Cell
PPageDesc = ptr TPageDesc PPageDesc = ptr PageDesc
TBitIndex = range[0..UnitsPerPage-1] BitIndex = range[0..UnitsPerPage-1]
TPageDesc {.final, pure.} = object PageDesc {.final, pure.} = object
next: PPageDesc # all nodes are connected with this pointer next: PPageDesc # all nodes are connected with this pointer
key: ByteAddress # start address at bit 0 key: ByteAddress # start address at bit 0
bits: array[TBitIndex, int] # a bit vector bits: array[BitIndex, int] # a bit vector
PPageDescArray = ptr array[0..1000_000, PPageDesc] PPageDescArray = ptr array[0..1000_000, PPageDesc]
TCellSet {.final, pure.} = object CellSet {.final, pure.} = object
counter, max: int counter, max: int
head: PPageDesc head: PPageDesc
data: PPageDescArray data: PPageDescArray
PCellArray = ptr array[0..100_000_000, PCell] PCellArray = ptr array[0..100_000_000, PCell]
TCellSeq {.final, pure.} = object CellSeq {.final, pure.} = object
len, cap: int len, cap: int
d: PCellArray d: PCellArray
{.deprecated: [TCell: Cell, TBitIndex: BitIndex, TPageDesc: PageDesc,
TRefCount: RefCount, TCellSet: CellSet, TCellSeq: CellSeq].}
# ------------------- cell seq handling --------------------------------------- # ------------------- cell seq handling ---------------------------------------
proc contains(s: TCellSeq, c: PCell): bool {.inline.} = proc contains(s: CellSeq, c: PCell): bool {.inline.} =
for i in 0 .. s.len-1: for i in 0 .. s.len-1:
if s.d[i] == c: return true if s.d[i] == c: return true
return false return false
proc add(s: var TCellSeq, c: PCell) {.inline.} = proc add(s: var CellSeq, c: PCell) {.inline.} =
if s.len >= s.cap: if s.len >= s.cap:
s.cap = s.cap * 3 div 2 s.cap = s.cap * 3 div 2
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
@ -59,12 +60,12 @@ proc add(s: var TCellSeq, c: PCell) {.inline.} =
s.d[s.len] = c s.d[s.len] = c
inc(s.len) inc(s.len)
proc init(s: var TCellSeq, cap: int = 1024) = proc init(s: var CellSeq, cap: int = 1024) =
s.len = 0 s.len = 0
s.cap = cap s.cap = cap
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell))) s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
proc deinit(s: var TCellSeq) = proc deinit(s: var CellSeq) =
dealloc(s.d) dealloc(s.d)
s.d = nil s.d = nil
s.len = 0 s.len = 0
@ -75,13 +76,13 @@ proc deinit(s: var TCellSeq) =
const const
InitCellSetSize = 1024 # must be a power of two! InitCellSetSize = 1024 # must be a power of two!
proc init(s: var TCellSet) = proc init(s: var CellSet) =
s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc))) s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
s.max = InitCellSetSize-1 s.max = InitCellSetSize-1
s.counter = 0 s.counter = 0
s.head = nil s.head = nil
proc deinit(s: var TCellSet) = proc deinit(s: var CellSet) =
var it = s.head var it = s.head
while it != nil: while it != nil:
var n = it.next var n = it.next
@ -98,14 +99,14 @@ proc nextTry(h, maxHash: int): int {.inline.} =
# generates each int in range(maxHash) exactly once (see any text on # generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof). # random-number generation for proof).
proc cellSetGet(t: TCellSet, key: ByteAddress): PPageDesc = proc cellSetGet(t: CellSet, key: ByteAddress): PPageDesc =
var h = cast[int](key) and t.max var h = cast[int](key) and t.max
while t.data[h] != nil: while t.data[h] != nil:
if t.data[h].key == key: return t.data[h] if t.data[h].key == key: return t.data[h]
h = nextTry(h, t.max) h = nextTry(h, t.max)
return nil return nil
proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) = proc cellSetRawInsert(t: CellSet, data: PPageDescArray, desc: PPageDesc) =
var h = cast[int](desc.key) and t.max var h = cast[int](desc.key) and t.max
while data[h] != nil: while data[h] != nil:
sysAssert(data[h] != desc, "CellSetRawInsert 1") sysAssert(data[h] != desc, "CellSetRawInsert 1")
@ -113,7 +114,7 @@ proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
sysAssert(data[h] == nil, "CellSetRawInsert 2") sysAssert(data[h] == nil, "CellSetRawInsert 2")
data[h] = desc data[h] = desc
proc cellSetEnlarge(t: var TCellSet) = proc cellSetEnlarge(t: var CellSet) =
var oldMax = t.max var oldMax = t.max
t.max = ((t.max+1)*2)-1 t.max = ((t.max+1)*2)-1
var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc))) var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
@ -123,7 +124,7 @@ proc cellSetEnlarge(t: var TCellSet) =
dealloc(t.data) dealloc(t.data)
t.data = n t.data = n
proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc = proc cellSetPut(t: var CellSet, key: ByteAddress): PPageDesc =
var h = cast[int](key) and t.max var h = cast[int](key) and t.max
while true: while true:
var x = t.data[h] var x = t.data[h]
@ -138,7 +139,7 @@ proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
while t.data[h] != nil: h = nextTry(h, t.max) while t.data[h] != nil: h = nextTry(h, t.max)
sysAssert(t.data[h] == nil, "CellSetPut") sysAssert(t.data[h] == nil, "CellSetPut")
# the new page descriptor goes into result # the new page descriptor goes into result
result = cast[PPageDesc](alloc0(sizeof(TPageDesc))) result = cast[PPageDesc](alloc0(sizeof(PageDesc)))
result.next = t.head result.next = t.head
result.key = key result.key = key
t.head = result t.head = result
@ -146,7 +147,7 @@ proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
# ---------- slightly higher level procs -------------------------------------- # ---------- slightly higher level procs --------------------------------------
proc contains(s: TCellSet, cell: PCell): bool = proc contains(s: CellSet, cell: PCell): bool =
var u = cast[ByteAddress](cell) var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift) var t = cellSetGet(s, u shr PageShift)
if t != nil: if t != nil:
@ -155,13 +156,13 @@ proc contains(s: TCellSet, cell: PCell): bool =
else: else:
result = false result = false
proc incl(s: var TCellSet, cell: PCell) {.noinline.} = proc incl(s: var CellSet, cell: PCell) {.noinline.} =
var u = cast[ByteAddress](cell) var u = cast[ByteAddress](cell)
var t = cellSetPut(s, u shr PageShift) var t = cellSetPut(s, u shr PageShift)
u = (u %% PageSize) /% MemAlign u = (u %% PageSize) /% MemAlign
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask)) t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TCellSet, cell: PCell) = proc excl(s: var CellSet, cell: PCell) =
var u = cast[ByteAddress](cell) var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift) var t = cellSetGet(s, u shr PageShift)
if t != nil: if t != nil:
@ -169,7 +170,7 @@ proc excl(s: var TCellSet, cell: PCell) =
t.bits[u shr IntShift] = (t.bits[u shr IntShift] and t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
not (1 shl (u and IntMask))) not (1 shl (u and IntMask)))
proc containsOrIncl(s: var TCellSet, cell: PCell): bool = proc containsOrIncl(s: var CellSet, cell: PCell): bool =
var u = cast[ByteAddress](cell) var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift) var t = cellSetGet(s, u shr PageShift)
if t != nil: if t != nil:
@ -182,7 +183,7 @@ proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
incl(s, cell) incl(s, cell)
result = false result = false
iterator elements(t: TCellSet): PCell {.inline.} = iterator elements(t: CellSet): PCell {.inline.} =
# while traversing it is forbidden to add pointers to the tree! # while traversing it is forbidden to add pointers to the tree!
var r = t.head var r = t.head
while r != nil: while r != nil:
@ -200,7 +201,7 @@ iterator elements(t: TCellSet): PCell {.inline.} =
inc(i) inc(i)
r = r.next r = r.next
iterator elementsExcept(t, s: TCellSet): PCell {.inline.} = iterator elementsExcept(t, s: CellSet): PCell {.inline.} =
var r = t.head var r = t.head
while r != nil: while r != nil:
let ss = cellSetGet(s, r.key) let ss = cellSetGet(s, r.key)

View file

@ -12,12 +12,13 @@
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.} proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
type type
TLibHandle = pointer # private type LibHandle = pointer # private type
TProcAddr = pointer # library loading and loading of procs: ProcAddr = pointer # library loading and loading of procs:
{.deprecated: [TLibHandle: LibHandle, TProcAddr: ProcAddr].}
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.} proc nimLoadLibrary(path: string): LibHandle {.compilerproc.}
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.} proc nimUnloadLibrary(lib: LibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.} proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {.compilerproc.}
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.} proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}

View file

@ -19,18 +19,20 @@ when not declared(NimString):
type type
pbytes = ptr array[0.. 0xffff, byte] pbytes = ptr array[0.. 0xffff, byte]
TRawChannel {.pure, final.} = object ## msg queue for a thread RawChannel {.pure, final.} = object ## msg queue for a thread
rd, wr, count, mask: int rd, wr, count, mask: int
data: pbytes data: pbytes
lock: TSysLock lock: SysLock
cond: TSysCond cond: SysCond
elemType: PNimType elemType: PNimType
ready: bool ready: bool
region: TMemRegion region: MemRegion
PRawChannel = ptr TRawChannel PRawChannel = ptr RawChannel
TLoadStoreMode = enum mStore, mLoad LoadStoreMode = enum mStore, mLoad
TChannel* {.gcsafe.}[TMsg] = TRawChannel ## a channel for thread communication Channel* {.gcsafe.}[TMsg] = RawChannel ## a channel for thread communication
{.deprecated: [TRawChannel: RawChannel, TLoadStoreMode: LoadStoreMode,
TChannel: Channel].}
const ChannelDeadMask = -2 const ChannelDeadMask = -2
proc initRawChannel(p: pointer) = proc initRawChannel(p: pointer) =
@ -49,9 +51,9 @@ proc deinitRawChannel(p: pointer) =
deinitSysCond(c.cond) deinitSysCond(c.cond)
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) {.benign.} mode: LoadStoreMode) {.benign.}
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
mode: TLoadStoreMode) {.benign.} = mode: LoadStoreMode) {.benign.} =
var var
d = cast[ByteAddress](dest) d = cast[ByteAddress](dest)
s = cast[ByteAddress](src) s = cast[ByteAddress](src)
@ -68,7 +70,7 @@ proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
of nkNone: sysAssert(false, "storeAux") of nkNone: sysAssert(false, "storeAux")
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) = mode: LoadStoreMode) =
var var
d = cast[ByteAddress](dest) d = cast[ByteAddress](dest)
s = cast[ByteAddress](src) s = cast[ByteAddress](src)
@ -202,7 +204,7 @@ template sendImpl(q: expr) {.immediate.} =
releaseSys(q.lock) releaseSys(q.lock)
signalSysCond(q.cond) signalSysCond(q.cond)
proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) = proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) =
## sends a message to a thread. `msg` is deeply copied. ## sends a message to a thread. `msg` is deeply copied.
var q = cast[PRawChannel](addr(c)) var q = cast[PRawChannel](addr(c))
sendImpl(q) sendImpl(q)
@ -218,7 +220,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
sysFatal(ValueError, "cannot receive message of wrong type") sysFatal(ValueError, "cannot receive message of wrong type")
rawRecv(q, res, typ) rawRecv(q, res, typ)
proc recv*[TMsg](c: var TChannel[TMsg]): TMsg = proc recv*[TMsg](c: var Channel[TMsg]): TMsg =
## receives a message from the channel `c`. This blocks until ## receives a message from the channel `c`. This blocks until
## a message has arrived! You may use ``peek`` to avoid the blocking. ## a message has arrived! You may use ``peek`` to avoid the blocking.
var q = cast[PRawChannel](addr(c)) var q = cast[PRawChannel](addr(c))
@ -226,7 +228,7 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result))) llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
releaseSys(q.lock) releaseSys(q.lock)
proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool, proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool,
msg: TMsg] = msg: TMsg] =
## try to receives a message from the channel `c` if available. Otherwise ## try to receives a message from the channel `c` if available. Otherwise
## it returns ``(false, default(msg))``. ## it returns ``(false, default(msg))``.
@ -238,7 +240,7 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
result.dataAvailable = true result.dataAvailable = true
releaseSys(q.lock) releaseSys(q.lock)
proc peek*[TMsg](c: var TChannel[TMsg]): int = proc peek*[TMsg](c: var Channel[TMsg]): int =
## returns the current number of messages in the channel `c`. Returns -1 ## returns the current number of messages in the channel `c`. Returns -1
## if the channel has been closed. **Note**: This is dangerous to use ## if the channel has been closed. **Note**: This is dangerous to use
## as it encourages races. It's much better to use ``tryRecv`` instead. ## as it encourages races. It's much better to use ``tryRecv`` instead.
@ -249,15 +251,15 @@ proc peek*[TMsg](c: var TChannel[TMsg]): int =
else: else:
result = -1 result = -1
proc open*[TMsg](c: var TChannel[TMsg]) = proc open*[TMsg](c: var Channel[TMsg]) =
## opens a channel `c` for inter thread communication. ## opens a channel `c` for inter thread communication.
initRawChannel(addr(c)) initRawChannel(addr(c))
proc close*[TMsg](c: var TChannel[TMsg]) = proc close*[TMsg](c: var Channel[TMsg]) =
## closes a channel `c` and frees its associated resources. ## closes a channel `c` and frees its associated resources.
deinitRawChannel(addr(c)) deinitRawChannel(addr(c))
proc ready*[TMsg](c: var TChannel[TMsg]): bool = proc ready*[TMsg](c: var Channel[TMsg]): bool =
## returns true iff some thread is waiting on the channel `c` for ## returns true iff some thread is waiting on the channel `c` for
## new messages. ## new messages.
var q = cast[PRawChannel](addr(c)) var q = cast[PRawChannel](addr(c))

View file

@ -10,22 +10,23 @@
## This file implements basic features for any debugger. ## This file implements basic features for any debugger.
type type
TVarSlot* {.compilerproc, final.} = object ## a slot in a frame VarSlot* {.compilerproc, final.} = object ## a slot in a frame
address*: pointer ## the variable's address address*: pointer ## the variable's address
typ*: PNimType ## the variable's type typ*: PNimType ## the variable's type
name*: cstring ## the variable's name; for globals this is "module.name" name*: cstring ## the variable's name; for globals this is "module.name"
PExtendedFrame = ptr TExtendedFrame PExtendedFrame = ptr ExtendedFrame
TExtendedFrame = object # If the debugger is enabled the compiler ExtendedFrame = object # If the debugger is enabled the compiler
# provides an extended frame. Of course # provides an extended frame. Of course
# only slots that are # only slots that are
# needed are allocated and not 10_000, # needed are allocated and not 10_000,
# except for the global data description. # except for the global data description.
f: TFrame f: Frame
slots: array[0..10_000, TVarSlot] slots: array[0..10_000, VarSlot]
{.deprecated: [TVarSlot: VarSlot, TExtendedFrame: ExtendedFrame].}
var var
dbgGlobalData: TExtendedFrame # this reserves much space, but dbgGlobalData: ExtendedFrame # this reserves much space, but
# for now it is the most practical way # for now it is the most practical way
proc dbgRegisterGlobal(name: cstring, address: pointer, proc dbgRegisterGlobal(name: cstring, address: pointer,
@ -39,7 +40,7 @@ proc dbgRegisterGlobal(name: cstring, address: pointer,
dbgGlobalData.slots[i].address = address dbgGlobalData.slots[i].address = address
inc(dbgGlobalData.f.len) inc(dbgGlobalData.f.len)
proc getLocal*(frame: PFrame; slot: int): TVarSlot {.inline.} = proc getLocal*(frame: PFrame; slot: int): VarSlot {.inline.} =
## retrieves the meta data for the local variable at `slot`. CAUTION: An ## retrieves the meta data for the local variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption! ## invalid `slot` value causes a corruption!
result = cast[PExtendedFrame](frame).slots[slot] result = cast[PExtendedFrame](frame).slots[slot]
@ -48,7 +49,7 @@ proc getGlobalLen*(): int {.inline.} =
## gets the number of registered globals. ## gets the number of registered globals.
result = dbgGlobalData.f.len result = dbgGlobalData.f.len
proc getGlobal*(slot: int): TVarSlot {.inline.} = proc getGlobal*(slot: int): VarSlot {.inline.} =
## retrieves the meta data for the global variable at `slot`. CAUTION: An ## retrieves the meta data for the global variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption! ## invalid `slot` value causes a corruption!
result = dbgGlobalData.slots[slot] result = dbgGlobalData.slots[slot]
@ -56,13 +57,13 @@ proc getGlobal*(slot: int): TVarSlot {.inline.} =
# ------------------- breakpoint support ------------------------------------ # ------------------- breakpoint support ------------------------------------
type type
TBreakpoint* = object ## represents a break point Breakpoint* = object ## represents a break point
low*, high*: int ## range from low to high; if disabled low*, high*: int ## range from low to high; if disabled
## both low and high are set to their negative values ## both low and high are set to their negative values
filename*: cstring ## the filename of the breakpoint filename*: cstring ## the filename of the breakpoint
var var
dbgBP: array[0..127, TBreakpoint] # breakpoints dbgBP: array[0..127, Breakpoint] # breakpoints
dbgBPlen: int dbgBPlen: int
dbgBPbloom: int64 # we use a bloom filter to speed up breakpoint checking dbgBPbloom: int64 # we use a bloom filter to speed up breakpoint checking
@ -131,16 +132,16 @@ proc canonFilename*(filename: cstring): cstring =
if fileMatches(result, filename): return result if fileMatches(result, filename): return result
result = nil result = nil
iterator listBreakpoints*(): ptr TBreakpoint = iterator listBreakpoints*(): ptr Breakpoint =
## lists all breakpoints. ## lists all breakpoints.
for i in 0..dbgBPlen-1: yield addr(dbgBP[i]) for i in 0..dbgBPlen-1: yield addr(dbgBP[i])
proc isActive*(b: ptr TBreakpoint): bool = b.low > 0 proc isActive*(b: ptr Breakpoint): bool = b.low > 0
proc flip*(b: ptr TBreakpoint) = proc flip*(b: ptr Breakpoint) =
## enables or disables 'b' depending on its current state. ## enables or disables 'b' depending on its current state.
b.low = -b.low; b.high = -b.high b.low = -b.low; b.high = -b.high
proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint = proc checkBreakpoints*(filename: cstring, line: int): ptr Breakpoint =
## in which breakpoint (if any) we are. ## in which breakpoint (if any) we are.
if (dbgBPbloom and line) != line: return nil if (dbgBPbloom and line) != line: return nil
for b in listBreakpoints(): for b in listBreakpoints():
@ -149,29 +150,30 @@ proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint =
# ------------------- watchpoint support ------------------------------------ # ------------------- watchpoint support ------------------------------------
type type
THash = int Hash = int
TWatchpoint {.pure, final.} = object Watchpoint {.pure, final.} = object
name: cstring name: cstring
address: pointer address: pointer
typ: PNimType typ: PNimType
oldValue: THash oldValue: Hash
{.deprecated: [THash: Hash, TWatchpoint: Watchpoint].}
var var
watchpoints: array [0..99, TWatchpoint] watchpoints: array [0..99, Watchpoint]
watchpointsLen: int watchpointsLen: int
proc `!&`(h: THash, val: int): THash {.inline.} = proc `!&`(h: Hash, val: int): Hash {.inline.} =
result = h +% val result = h +% val
result = result +% result shl 10 result = result +% result shl 10
result = result xor (result shr 6) result = result xor (result shr 6)
proc `!$`(h: THash): THash {.inline.} = proc `!$`(h: Hash): Hash {.inline.} =
result = h +% h shl 3 result = h +% h shl 3
result = result xor (result shr 11) result = result xor (result shr 11)
result = result +% result shl 15 result = result +% result shl 15
proc hash(data: pointer, size: int): THash = proc hash(data: pointer, size: int): Hash =
var h: THash = 0 var h: Hash = 0
var p = cast[cstring](data) var p = cast[cstring](data)
var i = 0 var i = 0
var s = size var s = size
@ -181,14 +183,14 @@ proc hash(data: pointer, size: int): THash =
dec(s) dec(s)
result = !$h result = !$h
proc hashGcHeader(data: pointer): THash = proc hashGcHeader(data: pointer): Hash =
const headerSize = sizeof(int)*2 const headerSize = sizeof(int)*2
result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize) result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize)
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: THash): THash h: Hash): Hash
proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool, proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
h: THash): THash = h: Hash): Hash =
var d = cast[ByteAddress](dest) var d = cast[ByteAddress](dest)
case n.kind case n.kind
of nkSlot: of nkSlot:
@ -204,7 +206,7 @@ proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
of nkNone: sysAssert(false, "genericHashAux") of nkNone: sysAssert(false, "genericHashAux")
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: THash): THash = h: Hash): Hash =
sysAssert(mt != nil, "genericHashAux 2") sysAssert(mt != nil, "genericHashAux 2")
case mt.kind case mt.kind
of tyString: of tyString:

View file

@ -15,7 +15,7 @@
{.push stack_trace: off.} {.push stack_trace: off.}
const const
NilLibHandle: TLibHandle = nil NilLibHandle: LibHandle = nil
proc rawWrite(f: File, s: string) = proc rawWrite(f: File, s: string) =
# we cannot throw an exception here! # we cannot throw an exception here!
@ -55,22 +55,22 @@ when defined(posix):
var var
RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".} proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: cstring, mode: int): TLibHandle {. proc dlopen(path: cstring, mode: int): LibHandle {.
importc, header: "<dlfcn.h>".} importc, header: "<dlfcn.h>".}
proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {. proc dlsym(lib: LibHandle, name: cstring): ProcAddr {.
importc, header: "<dlfcn.h>".} importc, header: "<dlfcn.h>".}
proc dlerror(): cstring {.importc, header: "<dlfcn.h>".} proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}
proc nimUnloadLibrary(lib: TLibHandle) = proc nimUnloadLibrary(lib: LibHandle) =
dlclose(lib) dlclose(lib)
proc nimLoadLibrary(path: string): TLibHandle = proc nimLoadLibrary(path: string): LibHandle =
result = dlopen(path, RTLD_NOW) result = dlopen(path, RTLD_NOW)
#c_fprintf(c_stdout, "%s\n", dlerror()) #c_fprintf(c_stdout, "%s\n", dlerror())
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr = proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
result = dlsym(lib, name) result = dlsym(lib, name)
if result == nil: procAddrError(name) if result == nil: procAddrError(name)
@ -84,12 +84,12 @@ elif defined(windows) or defined(dos):
type type
THINSTANCE {.importc: "HINSTANCE".} = object THINSTANCE {.importc: "HINSTANCE".} = object
x: pointer x: pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.} importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
else: else:
type type
THINSTANCE {.importc: "HINSTANCE".} = pointer THINSTANCE {.importc: "HINSTANCE".} = pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.} importc: "GetProcAddress", header: "<windows.h>", stdcall.}
proc freeLibrary(lib: THINSTANCE) {. proc freeLibrary(lib: THINSTANCE) {.
@ -97,13 +97,13 @@ elif defined(windows) or defined(dos):
proc winLoadLibrary(path: cstring): THINSTANCE {. proc winLoadLibrary(path: cstring): THINSTANCE {.
importc: "LoadLibraryA", header: "<windows.h>", stdcall.} importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
proc nimUnloadLibrary(lib: TLibHandle) = proc nimUnloadLibrary(lib: LibHandle) =
freeLibrary(cast[THINSTANCE](lib)) freeLibrary(cast[THINSTANCE](lib))
proc nimLoadLibrary(path: string): TLibHandle = proc nimLoadLibrary(path: string): LibHandle =
result = cast[TLibHandle](winLoadLibrary(path)) result = cast[LibHandle](winLoadLibrary(path))
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr = proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
result = getProcAddress(cast[THINSTANCE](lib), name) result = getProcAddress(cast[THINSTANCE](lib), name)
if result == nil: procAddrError(name) if result == nil: procAddrError(name)
@ -115,13 +115,13 @@ elif defined(mac):
# #
{.error: "no implementation for dyncalls yet".} {.error: "no implementation for dyncalls yet".}
proc nimUnloadLibrary(lib: TLibHandle) = proc nimUnloadLibrary(lib: LibHandle) =
NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES) NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
var var
dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
proc nimLoadLibrary(path: string): TLibHandle = proc nimLoadLibrary(path: string): LibHandle =
var var
img: NSObjectFileImage img: NSObjectFileImage
ret: NSObjectFileImageReturnCode ret: NSObjectFileImageReturnCode
@ -134,13 +134,13 @@ elif defined(mac):
modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
NSLINKMODULE_OPTION_RETURN_ON_ERROR) NSLINKMODULE_OPTION_RETURN_ON_ERROR)
NSDestroyObjectFileImage(img) NSDestroyObjectFileImage(img)
result = TLibHandle(modul) result = LibHandle(modul)
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr = proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
var var
nss: NSSymbol nss: NSSymbol
nss = NSLookupSymbolInModule(NSModule(lib), name) nss = NSLookupSymbolInModule(NSModule(lib), name)
result = TProcAddr(NSAddressOfSymbol(nss)) result = ProcAddr(NSAddressOfSymbol(nss))
if result == nil: ProcAddrError(name) if result == nil: ProcAddrError(name)
else: else:

View file

@ -20,63 +20,65 @@ const
EndbEnd = "***\n" EndbEnd = "***\n"
type type
TStaticStr = object StaticStr = object
len: int len: int
data: array[0..100, char] data: array[0..100, char]
TBreakpointFilename = object BreakpointFilename = object
b: ptr TBreakpoint b: ptr Breakpoint
filename: TStaticStr filename: StaticStr
TDbgState = enum DbgState = enum
dbOff, # debugger is turned off dbOff, # debugger is turned off
dbStepInto, # debugger is in tracing mode dbStepInto, # debugger is in tracing mode
dbStepOver, dbStepOver,
dbSkipCurrent, dbSkipCurrent,
dbQuiting, # debugger wants to quit dbQuiting, # debugger wants to quit
dbBreakpoints # debugger is only interested in breakpoints dbBreakpoints # debugger is only interested in breakpoints
{.deprecated: [TStaticStr: StaticStr, TBreakpointFilename: BreakpointFilename,
TDbgState: DbgState].}
var var
dbgUser: TStaticStr # buffer for user input; first command is ``step_into`` dbgUser: StaticStr # buffer for user input; first command is ``step_into``
# needs to be global cause we store the last command # needs to be global cause we store the last command
# in it # in it
dbgState: TDbgState # state of debugger dbgState: DbgState # state of debugger
dbgSkipToFrame: PFrame # frame to be skipped to dbgSkipToFrame: PFrame # frame to be skipped to
maxDisplayRecDepth: int = 5 # do not display too much data! maxDisplayRecDepth: int = 5 # do not display too much data!
brkPoints: array[0..127, TBreakpointFilename] brkPoints: array[0..127, BreakpointFilename]
proc setLen(s: var TStaticStr, newLen=0) = proc setLen(s: var StaticStr, newLen=0) =
s.len = newLen s.len = newLen
s.data[newLen] = '\0' s.data[newLen] = '\0'
proc add(s: var TStaticStr, c: char) = proc add(s: var StaticStr, c: char) =
if s.len < high(s.data)-1: if s.len < high(s.data)-1:
s.data[s.len] = c s.data[s.len] = c
s.data[s.len+1] = '\0' s.data[s.len+1] = '\0'
inc s.len inc s.len
proc add(s: var TStaticStr, c: cstring) = proc add(s: var StaticStr, c: cstring) =
var i = 0 var i = 0
while c[i] != '\0': while c[i] != '\0':
add s, c[i] add s, c[i]
inc i inc i
proc assign(s: var TStaticStr, c: cstring) = proc assign(s: var StaticStr, c: cstring) =
setLen(s) setLen(s)
add s, c add s, c
proc `==`(a, b: TStaticStr): bool = proc `==`(a, b: StaticStr): bool =
if a.len == b.len: if a.len == b.len:
for i in 0 .. a.len-1: for i in 0 .. a.len-1:
if a.data[i] != b.data[i]: return false if a.data[i] != b.data[i]: return false
return true return true
proc `==`(a: TStaticStr, b: cstring): bool = proc `==`(a: StaticStr, b: cstring): bool =
result = c_strcmp(a.data, b) == 0 result = c_strcmp(a.data, b) == 0
proc write(f: TFile, s: TStaticStr) = proc write(f: File, s: StaticStr) =
write(f, cstring(s.data)) write(f, cstring(s.data))
proc listBreakPoints() = proc listBreakPoints() =
@ -95,14 +97,14 @@ proc listBreakPoints() =
write(stdout, "\n") write(stdout, "\n")
write(stdout, EndbEnd) write(stdout, EndbEnd)
proc openAppend(filename: cstring): TFile = proc openAppend(filename: cstring): File =
var p: pointer = fopen(filename, "ab") var p: pointer = fopen(filename, "ab")
if p != nil: if p != nil:
result = cast[TFile](p) result = cast[File](p)
write(result, "----------------------------------------\n") write(result, "----------------------------------------\n")
proc dbgRepr(p: pointer, typ: PNimType): string = proc dbgRepr(p: pointer, typ: PNimType): string =
var cl: TReprClosure var cl: ReprClosure
initReprClosure(cl) initReprClosure(cl)
cl.recDepth = maxDisplayRecDepth cl.recDepth = maxDisplayRecDepth
# locks for the GC turned out to be a bad idea... # locks for the GC turned out to be a bad idea...
@ -112,12 +114,12 @@ proc dbgRepr(p: pointer, typ: PNimType): string =
# dec(recGcLock) # dec(recGcLock)
deinitReprClosure(cl) deinitReprClosure(cl)
proc writeVariable(stream: TFile, slot: TVarSlot) = proc writeVariable(stream: File, slot: VarSlot) =
write(stream, slot.name) write(stream, slot.name)
write(stream, " = ") write(stream, " = ")
writeln(stream, dbgRepr(slot.address, slot.typ)) writeln(stream, dbgRepr(slot.address, slot.typ))
proc listFrame(stream: TFile, f: PFrame) = proc listFrame(stream: File, f: PFrame) =
write(stream, EndbBeg) write(stream, EndbBeg)
write(stream, "| Frame (") write(stream, "| Frame (")
write(stream, f.len) write(stream, f.len)
@ -126,7 +128,7 @@ proc listFrame(stream: TFile, f: PFrame) =
writeln(stream, getLocal(f, i).name) writeln(stream, getLocal(f, i).name)
write(stream, EndbEnd) write(stream, EndbEnd)
proc listLocals(stream: TFile, f: PFrame) = proc listLocals(stream: File, f: PFrame) =
write(stream, EndbBeg) write(stream, EndbBeg)
write(stream, "| Frame (") write(stream, "| Frame (")
write(stream, f.len) write(stream, f.len)
@ -135,7 +137,7 @@ proc listLocals(stream: TFile, f: PFrame) =
writeVariable(stream, getLocal(f, i)) writeVariable(stream, getLocal(f, i))
write(stream, EndbEnd) write(stream, EndbEnd)
proc listGlobals(stream: TFile) = proc listGlobals(stream: File) =
write(stream, EndbBeg) write(stream, EndbBeg)
write(stream, "| Globals:\n") write(stream, "| Globals:\n")
for i in 0 .. getGlobalLen()-1: for i in 0 .. getGlobalLen()-1:
@ -172,7 +174,7 @@ proc dbgShowExecutionPoint() =
write(stdout, framePtr.procname) write(stdout, framePtr.procname)
write(stdout, " ***\n") write(stdout, " ***\n")
proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int = proc scanAndAppendWord(src: cstring, a: var StaticStr, start: int): int =
result = start result = start
# skip whitespace: # skip whitespace:
while src[result] in {'\t', ' '}: inc(result) while src[result] in {'\t', ' '}: inc(result)
@ -184,11 +186,11 @@ proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
else: break else: break
inc(result) inc(result)
proc scanWord(src: cstring, a: var TStaticStr, start: int): int = proc scanWord(src: cstring, a: var StaticStr, start: int): int =
setlen(a) setlen(a)
result = scanAndAppendWord(src, a, start) result = scanAndAppendWord(src, a, start)
proc scanFilename(src: cstring, a: var TStaticStr, start: int): int = proc scanFilename(src: cstring, a: var StaticStr, start: int): int =
result = start result = start
setLen a setLen a
while src[result] in {'\t', ' '}: inc(result) while src[result] in {'\t', ' '}: inc(result)
@ -250,8 +252,8 @@ proc hasExt(s: cstring): bool =
if s[i] == '.': return true if s[i] == '.': return true
inc i inc i
proc parseBreakpoint(s: cstring, start: int): TBreakpoint = proc parseBreakpoint(s: cstring, start: int): Breakpoint =
var dbgTemp: TStaticStr var dbgTemp: StaticStr
var i = scanNumber(s, result.low, start) var i = scanNumber(s, result.low, start)
if result.low == 0: result.low = framePtr.line if result.low == 0: result.low = framePtr.line
i = scanNumber(s, result.high, i) i = scanNumber(s, result.high, i)
@ -279,11 +281,11 @@ proc breakpointToggle(s: cstring, start: int) =
if not b.isNil: b.flip if not b.isNil: b.flip
else: debugOut("[Warning] unknown breakpoint ") else: debugOut("[Warning] unknown breakpoint ")
proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) = proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
var dbgTemp: TStaticStr var dbgTemp: StaticStr
var i = scanWord(s, dbgTemp, start) var i = scanWord(s, dbgTemp, start)
while s[i] in {' ', '\t'}: inc(i) while s[i] in {' ', '\t'}: inc(i)
var v: TVarSlot var v: VarSlot
if s[i] == '.': if s[i] == '.':
inc(i) inc(i)
add(dbgTemp, '.') add(dbgTemp, '.')
@ -299,7 +301,7 @@ proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) =
writeVariable(stream, v) writeVariable(stream, v)
proc dbgOut(s: cstring, start: int, currFrame: PFrame) = proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: TStaticStr var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start) var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0: if dbgTemp.len == 0:
invalidCommand() invalidCommand()
@ -312,7 +314,7 @@ proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
close(stream) close(stream)
proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) = proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: TStaticStr var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start) var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0: if dbgTemp.len == 0:
# just write it to stdout: # just write it to stdout:
@ -325,7 +327,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
listFrame(stream, currFrame) listFrame(stream, currFrame)
close(stream) close(stream)
proc readLine(f: TFile, line: var TStaticStr): bool = proc readLine(f: File, line: var StaticStr): bool =
while true: while true:
var c = fgetc(f) var c = fgetc(f)
if c < 0'i32: if c < 0'i32:
@ -358,7 +360,7 @@ proc commandPrompt() =
again = true again = true
dbgFramePtr = framePtr # for going down and up the stack dbgFramePtr = framePtr # for going down and up the stack
dbgDown = 0 # how often we did go down dbgDown = 0 # how often we did go down
dbgTemp: TStaticStr dbgTemp: StaticStr
while again: while again:
write(stdout, "*** endb| >>") write(stdout, "*** endb| >>")

View file

@ -365,5 +365,6 @@ when not defined(noSignalHandler):
proc setControlCHook(hook: proc () {.noconv.} not nil) = proc setControlCHook(hook: proc () {.noconv.} not nil) =
# ugly cast, but should work on all architectures: # ugly cast, but should work on all architectures:
type TSignalHandler = proc (sig: cint) {.noconv, benign.} type SignalHandler = proc (sig: cint) {.noconv, benign.}
c_signal(SIGINT, cast[TSignalHandler](hook)) {.deprecated: [TSignalHandler: SignalHandler].}
c_signal(SIGINT, cast[SignalHandler](hook))