lib/system/a-e - Dropped 'T' from types
This commit is contained in:
parent
d18e18060e
commit
ff5b446dfc
11 changed files with 270 additions and 252 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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 {.
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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| >>")
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue