lib/system/g-w - Dropped 'T' from types
This commit is contained in:
parent
ff5b446dfc
commit
2ca90a20a1
13 changed files with 426 additions and 396 deletions
|
|
@ -45,17 +45,17 @@ const
|
||||||
rcShift = 3 # shift by rcShift to get the reference counter
|
rcShift = 3 # shift by rcShift to get the reference counter
|
||||||
colorMask = 0b011
|
colorMask = 0b011
|
||||||
type
|
type
|
||||||
TWalkOp = enum
|
WalkOp = enum
|
||||||
waMarkGlobal, # part of the backup/debug mark&sweep
|
waMarkGlobal, # part of the backup/debug mark&sweep
|
||||||
waMarkPrecise, # part of the backup/debug mark&sweep
|
waMarkPrecise, # part of the backup/debug mark&sweep
|
||||||
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
||||||
waCollectWhite #, waDebug
|
waCollectWhite #, waDebug
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||||
# A ref type can have a finalizer that is called before the object's
|
# A ref type can have a finalizer that is called before the object's
|
||||||
# storage is freed.
|
# storage is freed.
|
||||||
|
|
||||||
TGcStat {.final, pure.} = object
|
GcStat {.final, pure.} = object
|
||||||
stackScans: int # number of performed stack scans (for statistics)
|
stackScans: int # number of performed stack scans (for statistics)
|
||||||
cycleCollections: int # number of performed full collections
|
cycleCollections: int # number of performed full collections
|
||||||
maxThreshold: int # max threshold that has been set
|
maxThreshold: int # max threshold that has been set
|
||||||
|
|
@ -64,35 +64,36 @@ type
|
||||||
cycleTableSize: int # max entries in cycle table
|
cycleTableSize: int # max entries in cycle table
|
||||||
maxPause: int64 # max measured GC pause in nanoseconds
|
maxPause: int64 # max measured GC pause in nanoseconds
|
||||||
|
|
||||||
TGcHeap {.final, pure.} = object # this contains the zero count and
|
GcHeap {.final, pure.} = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stackBottom: pointer
|
stackBottom: pointer
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
idGenerator: int
|
idGenerator: int
|
||||||
zct: TCellSeq # the zero count table
|
zct: CellSeq # the zero count table
|
||||||
decStack: TCellSeq # cells in the stack that are to decref again
|
decStack: CellSeq # cells in the stack that are to decref again
|
||||||
cycleRoots: TCellSet
|
cycleRoots: CellSet
|
||||||
tempStack: TCellSeq # temporary stack for recursion elimination
|
tempStack: CellSeq # temporary stack for recursion elimination
|
||||||
recGcLock: int # prevent recursion via finalizers; no thread lock
|
recGcLock: int # prevent recursion via finalizers; no thread lock
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
|
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
|
||||||
region: TMemRegion # garbage collected region
|
region: MemRegion # garbage collected region
|
||||||
stat: TGcStat
|
stat: GcStat
|
||||||
when useMarkForDebug or useBackupGc:
|
when useMarkForDebug or useBackupGc:
|
||||||
marked: TCellSet
|
marked: CellSet
|
||||||
|
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcHeap: GcHeap,
|
||||||
|
TGcStat: GcStat].}
|
||||||
var
|
var
|
||||||
gch {.rtlThreadVar.}: TGcHeap
|
gch {.rtlThreadVar.}: GcHeap
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
instantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
releaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
|
|
@ -104,18 +105,18 @@ template gcAssert(cond: bool, msg: string) =
|
||||||
writeStackTrace()
|
writeStackTrace()
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
|
proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
|
||||||
if (c.refcount and ZctFlag) == 0:
|
if (c.refcount and ZctFlag) == 0:
|
||||||
c.refcount = c.refcount or ZctFlag
|
c.refcount = c.refcount or ZctFlag
|
||||||
add(s, c)
|
add(s, c)
|
||||||
|
|
||||||
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
||||||
# convert object (=pointer to refcount) to pointer to userdata
|
# convert object (=pointer to refcount) to pointer to userdata
|
||||||
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
|
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
|
||||||
|
|
||||||
proc usrToCell(usr: pointer): PCell {.inline.} =
|
proc usrToCell(usr: pointer): PCell {.inline.} =
|
||||||
# convert pointer to userdata to object (=pointer to refcount)
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
|
||||||
|
|
||||||
proc canBeCycleRoot(c: PCell): bool {.inline.} =
|
proc canBeCycleRoot(c: PCell): bool {.inline.} =
|
||||||
result = ntfAcyclic notin c.typ.flags
|
result = ntfAcyclic notin c.typ.flags
|
||||||
|
|
@ -152,11 +153,11 @@ template gcTrace(cell, state: expr): stmt {.immediate.} =
|
||||||
when traceGC: traceCell(cell, state)
|
when traceGC: traceCell(cell, state)
|
||||||
|
|
||||||
# forward declarations:
|
# forward declarations:
|
||||||
proc collectCT(gch: var TGcHeap) {.benign.}
|
proc collectCT(gch: var GcHeap) {.benign.}
|
||||||
proc isOnStack*(p: pointer): bool {.noinline, benign.}
|
proc isOnStack*(p: pointer): bool {.noinline, benign.}
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
|
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
|
||||||
proc doOperation(p: pointer, op: TWalkOp) {.benign.}
|
proc doOperation(p: pointer, op: WalkOp) {.benign.}
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
||||||
# we need the prototype here for debugging purposes
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
|
|
@ -178,7 +179,7 @@ proc prepareDealloc(cell: PCell) =
|
||||||
# prevend recursive entering here by a lock.
|
# prevend recursive entering here by a lock.
|
||||||
# XXX: we should set the cell's children to nil!
|
# XXX: we should set the cell's children to nil!
|
||||||
inc(gch.recGcLock)
|
inc(gch.recGcLock)
|
||||||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
dec(gch.recGcLock)
|
dec(gch.recGcLock)
|
||||||
|
|
||||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||||
|
|
@ -276,7 +277,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
when traceGC:
|
when traceGC:
|
||||||
for i in low(TCellState)..high(TCellState): init(states[i])
|
for i in low(CellState)..high(CellState): init(states[i])
|
||||||
gch.cycleThreshold = InitialCycleThreshold
|
gch.cycleThreshold = InitialCycleThreshold
|
||||||
gch.stat.stackScans = 0
|
gch.stat.stackScans = 0
|
||||||
gch.stat.cycleCollections = 0
|
gch.stat.cycleCollections = 0
|
||||||
|
|
@ -308,12 +309,13 @@ proc setupForeignThreadGc*() =
|
||||||
|
|
||||||
when useMarkForDebug or useBackupGc:
|
when useMarkForDebug or useBackupGc:
|
||||||
type
|
type
|
||||||
TGlobalMarkerProc = proc () {.nimcall, benign.}
|
GlobalMarkerProc = proc () {.nimcall, benign.}
|
||||||
|
{.deprecated: [TGlobalMarkerProc: GlobalMarkerProc].}
|
||||||
var
|
var
|
||||||
globalMarkersLen: int
|
globalMarkersLen: int
|
||||||
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
|
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
|
||||||
|
|
||||||
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
|
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
|
||||||
if globalMarkersLen <= high(globalMarkers):
|
if globalMarkersLen <= high(globalMarkers):
|
||||||
globalMarkers[globalMarkersLen] = markerProc
|
globalMarkers[globalMarkersLen] = markerProc
|
||||||
inc globalMarkersLen
|
inc globalMarkersLen
|
||||||
|
|
@ -321,11 +323,11 @@ when useMarkForDebug or useBackupGc:
|
||||||
echo "[GC] cannot register global variable; too many global variables"
|
echo "[GC] cannot register global variable; too many global variables"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
proc cellsetReset(s: var TCellSet) =
|
proc cellsetReset(s: var CellSet) =
|
||||||
deinit(s)
|
deinit(s)
|
||||||
init(s)
|
init(s)
|
||||||
|
|
||||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
||||||
|
|
@ -345,7 +347,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
|
||||||
if m != nil: forAllSlotsAux(dest, m, op)
|
if m != nil: forAllSlotsAux(dest, m, op)
|
||||||
of nkNone: sysAssert(false, "forAllSlotsAux")
|
of nkNone: sysAssert(false, "forAllSlotsAux")
|
||||||
|
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
|
|
@ -359,7 +361,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
||||||
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
gcAssert(cell != nil, "forAllChildren: 1")
|
gcAssert(cell != nil, "forAllChildren: 1")
|
||||||
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
||||||
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
||||||
|
|
@ -380,7 +382,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||||
GenericSeqSize), cell.typ.base, op)
|
GenericSeqSize), cell.typ.base, op)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
|
||||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||||
# In 63% of all cases we succeed here! But we have to optimize the heck
|
# In 63% of all cases we succeed here! But we have to optimize the heck
|
||||||
# out of this small linear search so that ``newObj`` is not slowed down.
|
# out of this small linear search so that ``newObj`` is not slowed down.
|
||||||
|
|
@ -431,13 +433,13 @@ proc gcInvariant*() =
|
||||||
markForDebug(gch)
|
markForDebug(gch)
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
# now it is buffered in the ZCT
|
# now it is buffered in the ZCT
|
||||||
res.typ = typ
|
res.typ = typ
|
||||||
|
|
@ -486,7 +488,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
# now it is buffered in the ZCT
|
# now it is buffered in the ZCT
|
||||||
|
|
@ -515,7 +517,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var ol = usrToCell(old)
|
var ol = usrToCell(old)
|
||||||
|
|
@ -523,13 +525,13 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||||
sysAssert(allocInv(gch.region), "growObj begin")
|
sysAssert(allocInv(gch.region), "growObj begin")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
|
||||||
newsize-oldsize)
|
newsize-oldsize)
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
||||||
# This can be wrong for intermediate temps that are nevertheless on the
|
# This can be wrong for intermediate temps that are nevertheless on the
|
||||||
|
|
@ -564,7 +566,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
decRef(ol)
|
decRef(ol)
|
||||||
else:
|
else:
|
||||||
sysAssert(ol.typ != nil, "growObj: 5")
|
sysAssert(ol.typ != nil, "growObj: 5")
|
||||||
zeroMem(ol, sizeof(TCell))
|
zeroMem(ol, sizeof(Cell))
|
||||||
release(gch)
|
release(gch)
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
inc gch.idGenerator
|
inc gch.idGenerator
|
||||||
|
|
@ -580,7 +582,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||||
|
|
||||||
# ---------------- cycle collector -------------------------------------------
|
# ---------------- cycle collector -------------------------------------------
|
||||||
|
|
||||||
proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
proc freeCyclicCell(gch: var GcHeap, c: PCell) =
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
gcTrace(c, csCycFreed)
|
gcTrace(c, csCycFreed)
|
||||||
when logGC: writeCell("cycle collector dealloc cell", c)
|
when logGC: writeCell("cycle collector dealloc cell", c)
|
||||||
|
|
@ -589,7 +591,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
||||||
rawDealloc(gch.region, c)
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
gcAssert(c.typ != nil, "freeCyclicCell")
|
gcAssert(c.typ != nil, "freeCyclicCell")
|
||||||
zeroMem(c, sizeof(TCell))
|
zeroMem(c, sizeof(Cell))
|
||||||
|
|
||||||
proc markGray(s: PCell) =
|
proc markGray(s: PCell) =
|
||||||
if s.color != rcGray:
|
if s.color != rcGray:
|
||||||
|
|
@ -620,7 +622,7 @@ proc collectWhite(s: PCell) =
|
||||||
forAllChildren(s, waCollectWhite)
|
forAllChildren(s, waCollectWhite)
|
||||||
freeCyclicCell(gch, s)
|
freeCyclicCell(gch, s)
|
||||||
|
|
||||||
proc markRoots(gch: var TGcHeap) =
|
proc markRoots(gch: var GcHeap) =
|
||||||
var tabSize = 0
|
var tabSize = 0
|
||||||
for s in elements(gch.cycleRoots):
|
for s in elements(gch.cycleRoots):
|
||||||
#writeCell("markRoot", s)
|
#writeCell("markRoot", s)
|
||||||
|
|
@ -635,7 +637,7 @@ proc markRoots(gch: var TGcHeap) =
|
||||||
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
|
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
|
||||||
|
|
||||||
when useBackupGc:
|
when useBackupGc:
|
||||||
proc sweep(gch: var TGcHeap) =
|
proc sweep(gch: var GcHeap) =
|
||||||
for x in allObjects(gch.region):
|
for x in allObjects(gch.region):
|
||||||
if isCell(x):
|
if isCell(x):
|
||||||
# cast to PCell is correct here:
|
# cast to PCell is correct here:
|
||||||
|
|
@ -643,7 +645,7 @@ when useBackupGc:
|
||||||
if c notin gch.marked: freeCyclicCell(gch, c)
|
if c notin gch.marked: freeCyclicCell(gch, c)
|
||||||
|
|
||||||
when useMarkForDebug or useBackupGc:
|
when useMarkForDebug or useBackupGc:
|
||||||
proc markS(gch: var TGcHeap, c: PCell) =
|
proc markS(gch: var GcHeap, c: PCell) =
|
||||||
incl(gch.marked, c)
|
incl(gch.marked, c)
|
||||||
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
||||||
forAllChildren(c, waMarkPrecise)
|
forAllChildren(c, waMarkPrecise)
|
||||||
|
|
@ -653,10 +655,10 @@ when useMarkForDebug or useBackupGc:
|
||||||
if not containsOrIncl(gch.marked, d):
|
if not containsOrIncl(gch.marked, d):
|
||||||
forAllChildren(d, waMarkPrecise)
|
forAllChildren(d, waMarkPrecise)
|
||||||
|
|
||||||
proc markGlobals(gch: var TGcHeap) =
|
proc markGlobals(gch: var GcHeap) =
|
||||||
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||||
|
|
||||||
proc stackMarkS(gch: var TGcHeap, p: pointer) {.inline.} =
|
proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} =
|
||||||
# the addresses are not as cells on the stack, so turn them to cells:
|
# the addresses are not as cells on the stack, so turn them to cells:
|
||||||
var cell = usrToCell(p)
|
var cell = usrToCell(p)
|
||||||
var c = cast[TAddress](cell)
|
var c = cast[TAddress](cell)
|
||||||
|
|
@ -688,7 +690,7 @@ when logGC:
|
||||||
forAllChildren(s, waDebug)
|
forAllChildren(s, waDebug)
|
||||||
c_fprintf(c_stdout, "}\n")
|
c_fprintf(c_stdout, "}\n")
|
||||||
|
|
||||||
proc doOperation(p: pointer, op: TWalkOp) =
|
proc doOperation(p: pointer, op: WalkOp) =
|
||||||
if p == nil: return
|
if p == nil: return
|
||||||
var c: PCell = usrToCell(p)
|
var c: PCell = usrToCell(p)
|
||||||
gcAssert(c != nil, "doOperation: 1")
|
gcAssert(c != nil, "doOperation: 1")
|
||||||
|
|
@ -733,19 +735,19 @@ proc doOperation(p: pointer, op: TWalkOp) =
|
||||||
#of waDebug: debugGraph(c)
|
#of waDebug: debugGraph(c)
|
||||||
|
|
||||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||||
doOperation(d, TWalkOp(op))
|
doOperation(d, WalkOp(op))
|
||||||
|
|
||||||
proc collectZCT(gch: var TGcHeap): bool {.benign.}
|
proc collectZCT(gch: var GcHeap): bool {.benign.}
|
||||||
|
|
||||||
when useMarkForDebug or useBackupGc:
|
when useMarkForDebug or useBackupGc:
|
||||||
proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl,
|
proc markStackAndRegistersForSweep(gch: var GcHeap) {.noinline, cdecl,
|
||||||
benign.}
|
benign.}
|
||||||
|
|
||||||
proc collectRoots(gch: var TGcHeap) =
|
proc collectRoots(gch: var GcHeap) =
|
||||||
for s in elements(gch.cycleRoots):
|
for s in elements(gch.cycleRoots):
|
||||||
collectWhite(s)
|
collectWhite(s)
|
||||||
|
|
||||||
proc collectCycles(gch: var TGcHeap) =
|
proc collectCycles(gch: var GcHeap) =
|
||||||
# ensure the ZCT 'color' is not used:
|
# ensure the ZCT 'color' is not used:
|
||||||
while gch.zct.len > 0: discard collectZCT(gch)
|
while gch.zct.len > 0: discard collectZCT(gch)
|
||||||
when useBackupGc:
|
when useBackupGc:
|
||||||
|
|
@ -778,7 +780,7 @@ proc collectCycles(gch: var TGcHeap) =
|
||||||
if cycleRootsLen != 0:
|
if cycleRootsLen != 0:
|
||||||
cfprintf(cstdout, "cycle roots: %ld\n", cycleRootsLen)
|
cfprintf(cstdout, "cycle roots: %ld\n", cycleRootsLen)
|
||||||
|
|
||||||
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||||
# the addresses are not as cells on the stack, so turn them to cells:
|
# the addresses are not as cells on the stack, so turn them to cells:
|
||||||
sysAssert(allocInv(gch.region), "gcMark begin")
|
sysAssert(allocInv(gch.region), "gcMark begin")
|
||||||
var cell = usrToCell(p)
|
var cell = usrToCell(p)
|
||||||
|
|
@ -798,7 +800,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
add(gch.decStack, cell)
|
add(gch.decStack, cell)
|
||||||
sysAssert(allocInv(gch.region), "gcMark end")
|
sysAssert(allocInv(gch.region), "gcMark end")
|
||||||
|
|
||||||
proc markThreadStacks(gch: var TGcHeap) =
|
proc markThreadStacks(gch: var GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
{.error: "not fully implemented".}
|
{.error: "not fully implemented".}
|
||||||
var it = threadList
|
var it = threadList
|
||||||
|
|
@ -887,7 +889,7 @@ elif stackIncreases:
|
||||||
|
|
||||||
var
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a JmpBuf in the generated C code
|
||||||
# in a platform independent way
|
# in a platform independent way
|
||||||
|
|
||||||
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
||||||
|
|
@ -947,18 +949,18 @@ else:
|
||||||
gcMark(gch, cast[PPointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp +% sizeof(pointer)
|
sp = sp +% sizeof(pointer)
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
forEachStackSlot(gch, gcMark)
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
when useMarkForDebug or useBackupGc:
|
when useMarkForDebug or useBackupGc:
|
||||||
proc markStackAndRegistersForSweep(gch: var TGcHeap) =
|
proc markStackAndRegistersForSweep(gch: var GcHeap) =
|
||||||
forEachStackSlot(gch, stackMarkS)
|
forEachStackSlot(gch, stackMarkS)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# end of non-portable code
|
# end of non-portable code
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc collectZCT(gch: var TGcHeap): bool =
|
proc collectZCT(gch: var GcHeap): bool =
|
||||||
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
||||||
# deep freeing, which is bad for incremental operation. In order to
|
# deep freeing, which is bad for incremental operation. In order to
|
||||||
# avoid a deep stack, we move objects to keep the ZCT small.
|
# avoid a deep stack, we move objects to keep the ZCT small.
|
||||||
|
|
@ -968,7 +970,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
|
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
var steps = workPackage
|
var steps = workPackage
|
||||||
var t0: TTicks
|
var t0: Ticks
|
||||||
if gch.maxPause > 0: t0 = getticks()
|
if gch.maxPause > 0: t0 = getticks()
|
||||||
while L[] > 0:
|
while L[] > 0:
|
||||||
var c = gch.zct.d[0]
|
var c = gch.zct.d[0]
|
||||||
|
|
@ -1001,7 +1003,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
rawDealloc(gch.region, c)
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
sysAssert(c.typ != nil, "collectZCT 2")
|
sysAssert(c.typ != nil, "collectZCT 2")
|
||||||
zeroMem(c, sizeof(TCell))
|
zeroMem(c, sizeof(Cell))
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
if steps == 0:
|
if steps == 0:
|
||||||
steps = workPackage
|
steps = workPackage
|
||||||
|
|
@ -1014,7 +1016,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
return false
|
return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc unmarkStackAndRegisters(gch: var TGcHeap) =
|
proc unmarkStackAndRegisters(gch: var GcHeap) =
|
||||||
var d = gch.decStack.d
|
var d = gch.decStack.d
|
||||||
for i in 0..gch.decStack.len-1:
|
for i in 0..gch.decStack.len-1:
|
||||||
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
|
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
|
||||||
|
|
@ -1026,7 +1028,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
|
||||||
#sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
|
#sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
|
||||||
gch.decStack.len = 0
|
gch.decStack.len = 0
|
||||||
|
|
||||||
proc collectCTBody(gch: var TGcHeap) =
|
proc collectCTBody(gch: var GcHeap) =
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
let t0 = getticks()
|
let t0 = getticks()
|
||||||
sysAssert(allocInv(gch.region), "collectCT: begin")
|
sysAssert(allocInv(gch.region), "collectCT: begin")
|
||||||
|
|
@ -1058,11 +1060,11 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
|
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
|
||||||
|
|
||||||
when useMarkForDebug or useBackupGc:
|
when useMarkForDebug or useBackupGc:
|
||||||
proc markForDebug(gch: var TGcHeap) =
|
proc markForDebug(gch: var GcHeap) =
|
||||||
markStackAndRegistersForSweep(gch)
|
markStackAndRegistersForSweep(gch)
|
||||||
markGlobals(gch)
|
markGlobals(gch)
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
proc collectCT(gch: var GcHeap) =
|
||||||
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
||||||
# becomes more expensive with large stacks and large stacks mean that
|
# becomes more expensive with large stacks and large stacks mean that
|
||||||
# cells with RC=0 are more likely to be kept alive by the stack.
|
# cells with RC=0 are more likely to be kept alive by the stack.
|
||||||
|
|
@ -1077,13 +1079,13 @@ proc collectCT(gch: var TGcHeap) =
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
proc toNano(x: int): TNanos {.inline.} =
|
proc toNano(x: int): Nanos {.inline.} =
|
||||||
result = x * 1000
|
result = x * 1000
|
||||||
|
|
||||||
proc GC_setMaxPause*(MaxPauseInUs: int) =
|
proc GC_setMaxPause*(MaxPauseInUs: int) =
|
||||||
gch.maxPause = MaxPauseInUs.toNano
|
gch.maxPause = MaxPauseInUs.toNano
|
||||||
|
|
||||||
proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
|
proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gch.maxPause = us.toNano
|
gch.maxPause = us.toNano
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const
|
||||||
# was replaced by a resize operation.
|
# was replaced by a resize operation.
|
||||||
# see growObj for details
|
# see growObj for details
|
||||||
|
|
||||||
rcColorMask = TRefCount(0b00111)
|
rcColorMask = RefCount(0b00111)
|
||||||
|
|
||||||
rcZct = 0b01000 # already added to ZCT
|
rcZct = 0b01000 # already added to ZCT
|
||||||
rcInCycleRoots = 0b10000 # already buffered as cycle candidate
|
rcInCycleRoots = 0b10000 # already buffered as cycle candidate
|
||||||
|
|
@ -97,14 +97,14 @@ const
|
||||||
CollectCyclesStats = false
|
CollectCyclesStats = false
|
||||||
|
|
||||||
type
|
type
|
||||||
TWalkOp = enum
|
WalkOp = enum
|
||||||
waPush
|
waPush
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
|
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
|
||||||
# A ref type can have a finalizer that is called before the object's
|
# A ref type can have a finalizer that is called before the object's
|
||||||
# storage is freed.
|
# storage is freed.
|
||||||
|
|
||||||
TGcStat {.final, pure.} = object
|
GcStat {.final, pure.} = object
|
||||||
stackScans: int # number of performed stack scans (for statistics)
|
stackScans: int # number of performed stack scans (for statistics)
|
||||||
cycleCollections: int # number of performed full collections
|
cycleCollections: int # number of performed full collections
|
||||||
maxThreshold: int # max threshold that has been set
|
maxThreshold: int # max threshold that has been set
|
||||||
|
|
@ -113,16 +113,16 @@ type
|
||||||
cycleTableSize: int # max entries in cycle table
|
cycleTableSize: int # max entries in cycle table
|
||||||
maxPause: int64 # max measured GC pause in nanoseconds
|
maxPause: int64 # max measured GC pause in nanoseconds
|
||||||
|
|
||||||
TGcHeap {.final, pure.} = object # this contains the zero count and
|
GcHeap {.final, pure.} = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stackBottom: pointer
|
stackBottom: pointer
|
||||||
stackTop: pointer
|
stackTop: pointer
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
zct: TCellSeq # the zero count table
|
zct: CellSeq # the zero count table
|
||||||
decStack: TCellSeq # cells in the stack that are to decref again
|
decStack: CellSeq # cells in the stack that are to decref again
|
||||||
cycleRoots: TCellSeq
|
cycleRoots: CellSeq
|
||||||
tempStack: TCellSeq # temporary stack for recursion elimination
|
tempStack: CellSeq # temporary stack for recursion elimination
|
||||||
freeStack: TCellSeq # objects ready to be freed
|
freeStack: CellSeq # objects ready to be freed
|
||||||
recGcLock: int # prevent recursion via finalizers; no thread lock
|
recGcLock: int # prevent recursion via finalizers; no thread lock
|
||||||
cycleRootsTrimIdx: int # Trimming is a light-weight collection of the
|
cycleRootsTrimIdx: int # Trimming is a light-weight collection of the
|
||||||
# cycle roots table that uses a cheap linear scan
|
# cycle roots table that uses a cheap linear scan
|
||||||
|
|
@ -132,21 +132,22 @@ type
|
||||||
# This index indicates the start of the range of
|
# This index indicates the start of the range of
|
||||||
# such new objects within the table.
|
# such new objects within the table.
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
|
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
|
||||||
region: TMemRegion # garbage collected region
|
region: MemRegion # garbage collected region
|
||||||
stat: TGcStat
|
stat: GcStat
|
||||||
|
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcStat: GcStat,
|
||||||
|
TGcHeap: GcHeap].}
|
||||||
var
|
var
|
||||||
gch* {.rtlThreadVar.}: TGcHeap
|
gch* {.rtlThreadVar.}: GcHeap
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
instantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
AcquireSys(HeapLock)
|
AcquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
releaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
|
|
@ -169,7 +170,7 @@ template isDead(c: Pcell): expr =
|
||||||
c.isBitUp(rcReallyDead) # also covers rcRetiredBuffer
|
c.isBitUp(rcReallyDead) # also covers rcRetiredBuffer
|
||||||
|
|
||||||
template clearBit(c: PCell, bit): expr =
|
template clearBit(c: PCell, bit): expr =
|
||||||
c.refcount = c.refcount and (not TRefCount(bit))
|
c.refcount = c.refcount and (not RefCount(bit))
|
||||||
|
|
||||||
when debugGC:
|
when debugGC:
|
||||||
var gcCollectionIdx = 0
|
var gcCollectionIdx = 0
|
||||||
|
|
@ -206,7 +207,7 @@ when debugGC:
|
||||||
c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld\n",
|
c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld\n",
|
||||||
msg, c, kind, c.refcount shr rcShift)
|
msg, c, kind, c.refcount shr rcShift)
|
||||||
|
|
||||||
proc addZCT(zct: var TCellSeq, c: PCell) {.noinline.} =
|
proc addZCT(zct: var CellSeq, c: PCell) {.noinline.} =
|
||||||
if c.isBitDown(rcZct):
|
if c.isBitDown(rcZct):
|
||||||
c.setBit rcZct
|
c.setBit rcZct
|
||||||
zct.add c
|
zct.add c
|
||||||
|
|
@ -221,7 +222,7 @@ template setStackTop(gch) =
|
||||||
var stackTop {.volatile.}: pointer
|
var stackTop {.volatile.}: pointer
|
||||||
gch.stackTop = addr(stackTop)
|
gch.stackTop = addr(stackTop)
|
||||||
|
|
||||||
template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
|
template addCycleRoot(cycleRoots: var CellSeq, c: PCell) =
|
||||||
if c.color != rcCycleCandidate:
|
if c.color != rcCycleCandidate:
|
||||||
c.setColor rcCycleCandidate
|
c.setColor rcCycleCandidate
|
||||||
|
|
||||||
|
|
@ -233,11 +234,11 @@ template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
|
||||||
|
|
||||||
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
||||||
# convert object (=pointer to refcount) to pointer to userdata
|
# convert object (=pointer to refcount) to pointer to userdata
|
||||||
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
|
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
|
||||||
|
|
||||||
proc usrToCell*(usr: pointer): PCell {.inline.} =
|
proc usrToCell*(usr: pointer): PCell {.inline.} =
|
||||||
# convert pointer to userdata to object (=pointer to refcount)
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
|
||||||
|
|
||||||
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
||||||
result = ntfAcyclic notin c.typ.flags
|
result = ntfAcyclic notin c.typ.flags
|
||||||
|
|
@ -254,11 +255,11 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
|
||||||
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
||||||
|
|
||||||
# forward declarations:
|
# forward declarations:
|
||||||
proc collectCT(gch: var TGcHeap)
|
proc collectCT(gch: var GcHeap)
|
||||||
proc isOnStack*(p: pointer): bool {.noinline.}
|
proc isOnStack*(p: pointer): bool {.noinline.}
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp)
|
proc forAllChildren(cell: PCell, op: WalkOp)
|
||||||
proc doOperation(p: pointer, op: TWalkOp)
|
proc doOperation(p: pointer, op: WalkOp)
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp)
|
||||||
# we need the prototype here for debugging purposes
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
|
@ -269,18 +270,19 @@ proc prepareDealloc(cell: PCell) =
|
||||||
# prevend recursive entering here by a lock.
|
# prevend recursive entering here by a lock.
|
||||||
# XXX: we should set the cell's children to nil!
|
# XXX: we should set the cell's children to nil!
|
||||||
inc(gch.recGcLock)
|
inc(gch.recGcLock)
|
||||||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
dec(gch.recGcLock)
|
dec(gch.recGcLock)
|
||||||
|
|
||||||
when traceGC:
|
when traceGC:
|
||||||
# traceGC is a special switch to enable extensive debugging
|
# traceGC is a special switch to enable extensive debugging
|
||||||
type
|
type
|
||||||
TCellState = enum
|
CellState = enum
|
||||||
csAllocated, csFreed
|
csAllocated, csFreed
|
||||||
|
{.deprecated: [TCellState: CellState].}
|
||||||
var
|
var
|
||||||
states: array[TCellState, TCellSet]
|
states: array[CellState, CellSet]
|
||||||
|
|
||||||
proc traceCell(c: PCell, state: TCellState) =
|
proc traceCell(c: PCell, state: CellState) =
|
||||||
case state
|
case state
|
||||||
of csAllocated:
|
of csAllocated:
|
||||||
if c in states[csAllocated]:
|
if c in states[csAllocated]:
|
||||||
|
|
@ -300,7 +302,7 @@ when traceGC:
|
||||||
incl(states[state], c)
|
incl(states[state], c)
|
||||||
|
|
||||||
proc computeCellWeight(c: PCell): int =
|
proc computeCellWeight(c: PCell): int =
|
||||||
var x: TCellSet
|
var x: CellSet
|
||||||
x.init
|
x.init
|
||||||
|
|
||||||
let startLen = gch.tempStack.len
|
let startLen = gch.tempStack.len
|
||||||
|
|
@ -363,30 +365,32 @@ proc rtlAddZCT(c: PCell) {.rtl, inl.} =
|
||||||
WithHeapLock: addZCT(gch.zct, c)
|
WithHeapLock: addZCT(gch.zct, c)
|
||||||
|
|
||||||
type
|
type
|
||||||
TCyclicMode = enum
|
CyclicMode = enum
|
||||||
Cyclic,
|
Cyclic,
|
||||||
Acyclic,
|
Acyclic,
|
||||||
MaybeCyclic
|
MaybeCyclic
|
||||||
|
|
||||||
TReleaseType = enum
|
ReleaseType = enum
|
||||||
AddToZTC
|
AddToZTC
|
||||||
FreeImmediately
|
FreeImmediately
|
||||||
|
|
||||||
THeapType = enum
|
HeapType = enum
|
||||||
LocalHeap
|
LocalHeap
|
||||||
SharedHeap
|
SharedHeap
|
||||||
|
{.deprecated: [TCyclicMode: CyclicMode, TReleaseType: ReleaseType,
|
||||||
|
THeapType: HeapType].}
|
||||||
|
|
||||||
template `++` (rc: TRefCount, heapType: THeapType): stmt =
|
template `++` (rc: RefCount, heapType: HeapType): stmt =
|
||||||
when heapType == SharedHeap:
|
when heapType == SharedHeap:
|
||||||
discard atomicInc(rc, rcIncrement)
|
discard atomicInc(rc, rcIncrement)
|
||||||
else:
|
else:
|
||||||
inc rc, rcIncrement
|
inc rc, rcIncrement
|
||||||
|
|
||||||
template `--`(rc: TRefCount): expr =
|
template `--`(rc: RefCount): expr =
|
||||||
dec rc, rcIncrement
|
dec rc, rcIncrement
|
||||||
rc <% rcIncrement
|
rc <% rcIncrement
|
||||||
|
|
||||||
template `--` (rc: TRefCount, heapType: THeapType): expr =
|
template `--` (rc: RefCount, heapType: HeapType): expr =
|
||||||
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
|
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
|
||||||
|
|
||||||
template doDecRef(cc: PCell,
|
template doDecRef(cc: PCell,
|
||||||
|
|
@ -479,7 +483,7 @@ when hasThreadSupport and hasSharedHeap:
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
when traceGC:
|
when traceGC:
|
||||||
for i in low(TCellState)..high(TCellState): init(states[i])
|
for i in low(CellState)..high(CellState): init(states[i])
|
||||||
gch.cycleThreshold = InitialCycleThreshold
|
gch.cycleThreshold = InitialCycleThreshold
|
||||||
gch.stat.stackScans = 0
|
gch.stat.stackScans = 0
|
||||||
gch.stat.cycleCollections = 0
|
gch.stat.cycleCollections = 0
|
||||||
|
|
@ -494,7 +498,7 @@ proc initGC() =
|
||||||
init(gch.cycleRoots)
|
init(gch.cycleRoots)
|
||||||
init(gch.decStack)
|
init(gch.decStack)
|
||||||
|
|
||||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
||||||
|
|
@ -514,7 +518,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
if m != nil: forAllSlotsAux(dest, m, op)
|
if m != nil: forAllSlotsAux(dest, m, op)
|
||||||
of nkNone: sysAssert(false, "forAllSlotsAux")
|
of nkNone: sysAssert(false, "forAllSlotsAux")
|
||||||
|
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
|
|
@ -528,7 +532,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
||||||
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
sysAssert(cell != nil, "forAllChildren: 1")
|
sysAssert(cell != nil, "forAllChildren: 1")
|
||||||
sysAssert(cell.typ != nil, "forAllChildren: 2")
|
sysAssert(cell.typ != nil, "forAllChildren: 2")
|
||||||
sysAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
|
sysAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
|
||||||
|
|
@ -549,7 +553,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||||
cell.typ.base, op)
|
cell.typ.base, op)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
|
||||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||||
# In 63% of all cases we succeed here! But we have to optimize the heck
|
# In 63% of all cases we succeed here! But we have to optimize the heck
|
||||||
# out of this small linear search so that ``newObj`` is not slowed down.
|
# out of this small linear search so that ``newObj`` is not slowed down.
|
||||||
|
|
@ -593,7 +597,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
return
|
return
|
||||||
add(gch.zct, res)
|
add(gch.zct, res)
|
||||||
|
|
||||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
|
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap, rc1 = false): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
|
|
@ -602,7 +606,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj after collect")
|
sysAssert(allocInv(gch.region), "rawNewObj after collect")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
|
sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
|
||||||
|
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
|
|
@ -638,20 +642,20 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc freeCell(gch: var TGcHeap, c: PCell) =
|
proc freeCell(gch: var GcHeap, c: PCell) =
|
||||||
# prepareDealloc(c)
|
# prepareDealloc(c)
|
||||||
gcTrace(c, csFreed)
|
gcTrace(c, csFreed)
|
||||||
|
|
||||||
when reallyDealloc: rawDealloc(gch.region, c)
|
when reallyDealloc: rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
sysAssert(c.typ != nil, "collectCycles")
|
sysAssert(c.typ != nil, "collectCycles")
|
||||||
zeroMem(c, sizeof(TCell))
|
zeroMem(c, sizeof(Cell))
|
||||||
|
|
||||||
template eraseAt(cells: var TCellSeq, at: int): stmt =
|
template eraseAt(cells: var CellSeq, at: int): stmt =
|
||||||
cells.d[at] = cells.d[cells.len - 1]
|
cells.d[at] = cells.d[cells.len - 1]
|
||||||
dec cells.len
|
dec cells.len
|
||||||
|
|
||||||
template trimAt(roots: var TCellSeq, at: int): stmt =
|
template trimAt(roots: var CellSeq, at: int): stmt =
|
||||||
# This will remove a cycle root candidate during trimming.
|
# This will remove a cycle root candidate during trimming.
|
||||||
# a candidate is removed either because it received a refup and
|
# a candidate is removed either because it received a refup and
|
||||||
# it's no longer a candidate or because it received further refdowns
|
# it's no longer a candidate or because it received further refdowns
|
||||||
|
|
@ -696,7 +700,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var ol = usrToCell(old)
|
var ol = usrToCell(old)
|
||||||
|
|
@ -704,7 +708,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||||
sysAssert(allocInv(gch.region), "growObj begin")
|
sysAssert(allocInv(gch.region), "growObj begin")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||||
var elemSize = if ol.typ.kind != tyString: ol.typ.base.size
|
var elemSize = if ol.typ.kind != tyString: ol.typ.base.size
|
||||||
else: 1
|
else: 1
|
||||||
|
|
||||||
|
|
@ -713,8 +717,8 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
# XXX: This should happen outside
|
# XXX: This should happen outside
|
||||||
# call user-defined move code
|
# call user-defined move code
|
||||||
# call user-defined default constructor
|
# call user-defined default constructor
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
|
||||||
newsize-oldsize)
|
newsize-oldsize)
|
||||||
|
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
||||||
|
|
@ -778,26 +782,27 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||||
|
|
||||||
# ---------------- cycle collector -------------------------------------------
|
# ---------------- cycle collector -------------------------------------------
|
||||||
|
|
||||||
proc doOperation(p: pointer, op: TWalkOp) =
|
proc doOperation(p: pointer, op: WalkOp) =
|
||||||
if p == nil: return
|
if p == nil: return
|
||||||
var c: PCell = usrToCell(p)
|
var c: PCell = usrToCell(p)
|
||||||
sysAssert(c != nil, "doOperation: 1")
|
sysAssert(c != nil, "doOperation: 1")
|
||||||
gch.tempStack.add c
|
gch.tempStack.add c
|
||||||
|
|
||||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||||
doOperation(d, TWalkOp(op))
|
doOperation(d, WalkOp(op))
|
||||||
|
|
||||||
type
|
type
|
||||||
TRecursionType = enum
|
RecursionType = enum
|
||||||
FromChildren,
|
FromChildren,
|
||||||
FromRoot
|
FromRoot
|
||||||
|
{.deprecated: [TRecursionType: RecursionType].}
|
||||||
|
|
||||||
proc collectZCT(gch: var TGcHeap): bool
|
proc collectZCT(gch: var GcHeap): bool
|
||||||
|
|
||||||
template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
|
template pseudoRecursion(typ: RecursionType, body: stmt): stmt =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
|
proc trimCycleRoots(gch: var GcHeap, startIdx = gch.cycleRootsTrimIdx) =
|
||||||
var i = startIdx
|
var i = startIdx
|
||||||
while i < gch.cycleRoots.len:
|
while i < gch.cycleRoots.len:
|
||||||
if gch.cycleRoots.d[i].color != rcCycleCandidate:
|
if gch.cycleRoots.d[i].color != rcCycleCandidate:
|
||||||
|
|
@ -808,7 +813,7 @@ proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
|
||||||
gch.cycleRootsTrimIdx = gch.cycleRoots.len
|
gch.cycleRootsTrimIdx = gch.cycleRoots.len
|
||||||
|
|
||||||
# we now use a much simpler and non-recursive algorithm for cycle removal
|
# we now use a much simpler and non-recursive algorithm for cycle removal
|
||||||
proc collectCycles(gch: var TGcHeap) =
|
proc collectCycles(gch: var GcHeap) =
|
||||||
if gch.cycleRoots.len == 0: return
|
if gch.cycleRoots.len == 0: return
|
||||||
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, gch.cycleRoots.len)
|
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, gch.cycleRoots.len)
|
||||||
|
|
||||||
|
|
@ -990,7 +995,7 @@ var gcDebugging* = false
|
||||||
|
|
||||||
var seqdbg* : proc (s: PGenericSeq) {.cdecl.}
|
var seqdbg* : proc (s: PGenericSeq) {.cdecl.}
|
||||||
|
|
||||||
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||||
# the addresses are not as cells on the stack, so turn them to cells:
|
# the addresses are not as cells on the stack, so turn them to cells:
|
||||||
sysAssert(allocInv(gch.region), "gcMark begin")
|
sysAssert(allocInv(gch.region), "gcMark begin")
|
||||||
var cell = usrToCell(p)
|
var cell = usrToCell(p)
|
||||||
|
|
@ -1025,7 +1030,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
add(gch.decStack, cell)
|
add(gch.decStack, cell)
|
||||||
sysAssert(allocInv(gch.region), "gcMark end")
|
sysAssert(allocInv(gch.region), "gcMark end")
|
||||||
|
|
||||||
proc markThreadStacks(gch: var TGcHeap) =
|
proc markThreadStacks(gch: var GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
{.error: "not fully implemented".}
|
{.error: "not fully implemented".}
|
||||||
var it = threadList
|
var it = threadList
|
||||||
|
|
@ -1074,7 +1079,7 @@ proc stackSize(): int {.noinline.} =
|
||||||
|
|
||||||
var
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a JmpBuf in the generated C code
|
||||||
# in a platform independent way
|
# in a platform independent way
|
||||||
|
|
||||||
when defined(sparc): # For SPARC architecture.
|
when defined(sparc): # For SPARC architecture.
|
||||||
|
|
@ -1086,7 +1091,7 @@ when defined(sparc): # For SPARC architecture.
|
||||||
var x = cast[ByteAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
when defined(sparcv9):
|
when defined(sparcv9):
|
||||||
asm """"flushw \n" """
|
asm """"flushw \n" """
|
||||||
else:
|
else:
|
||||||
|
|
@ -1117,7 +1122,7 @@ elif stackIncreases:
|
||||||
var x = cast[ByteAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
var registers: C_JmpBuf
|
var registers: C_JmpBuf
|
||||||
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
||||||
var max = cast[ByteAddress](gch.stackBottom)
|
var max = cast[ByteAddress](gch.stackBottom)
|
||||||
|
|
@ -1140,7 +1145,7 @@ else:
|
||||||
var x = cast[ByteAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
# We use a jmp_buf buffer that is in the C stack.
|
# We use a jmp_buf buffer that is in the C stack.
|
||||||
# Used to traverse the stack and registers assuming
|
# Used to traverse the stack and registers assuming
|
||||||
# that 'setjmp' will save registers in the C stack.
|
# that 'setjmp' will save registers in the C stack.
|
||||||
|
|
@ -1181,7 +1186,7 @@ else:
|
||||||
# end of non-portable code
|
# end of non-portable code
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc releaseCell(gch: var TGcHeap, cell: PCell) =
|
proc releaseCell(gch: var GcHeap, cell: PCell) =
|
||||||
if cell.color != rcReallyDead:
|
if cell.color != rcReallyDead:
|
||||||
prepareDealloc(cell)
|
prepareDealloc(cell)
|
||||||
cell.setColor rcReallyDead
|
cell.setColor rcReallyDead
|
||||||
|
|
@ -1210,13 +1215,13 @@ proc releaseCell(gch: var TGcHeap, cell: PCell) =
|
||||||
# recursion).
|
# recursion).
|
||||||
# We can ignore it now as the ZCT cleaner will reach it soon.
|
# We can ignore it now as the ZCT cleaner will reach it soon.
|
||||||
|
|
||||||
proc collectZCT(gch: var TGcHeap): bool =
|
proc collectZCT(gch: var GcHeap): bool =
|
||||||
const workPackage = 100
|
const workPackage = 100
|
||||||
var L = addr(gch.zct.len)
|
var L = addr(gch.zct.len)
|
||||||
|
|
||||||
when withRealtime:
|
when withRealtime:
|
||||||
var steps = workPackage
|
var steps = workPackage
|
||||||
var t0: TTicks
|
var t0: Ticks
|
||||||
if gch.maxPause > 0: t0 = getticks()
|
if gch.maxPause > 0: t0 = getticks()
|
||||||
|
|
||||||
while L[] > 0:
|
while L[] > 0:
|
||||||
|
|
@ -1257,7 +1262,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
#deInit(gch.zct)
|
#deInit(gch.zct)
|
||||||
#init(gch.zct)
|
#init(gch.zct)
|
||||||
|
|
||||||
proc unmarkStackAndRegisters(gch: var TGcHeap) =
|
proc unmarkStackAndRegisters(gch: var GcHeap) =
|
||||||
var d = gch.decStack.d
|
var d = gch.decStack.d
|
||||||
for i in 0 .. <gch.decStack.len:
|
for i in 0 .. <gch.decStack.len:
|
||||||
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
|
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
|
||||||
|
|
@ -1283,7 +1288,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
|
||||||
|
|
||||||
gch.decStack.len = 0
|
gch.decStack.len = 0
|
||||||
|
|
||||||
proc collectCTBody(gch: var TGcHeap) =
|
proc collectCTBody(gch: var GcHeap) =
|
||||||
when withRealtime:
|
when withRealtime:
|
||||||
let t0 = getticks()
|
let t0 = getticks()
|
||||||
when debugGC: inc gcCollectionIdx
|
when debugGC: inc gcCollectionIdx
|
||||||
|
|
@ -1315,20 +1320,20 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
if gch.maxPause > 0 and duration > gch.maxPause:
|
if gch.maxPause > 0 and duration > gch.maxPause:
|
||||||
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
|
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
proc collectCT(gch: var GcHeap) =
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||||
gch.recGcLock == 0:
|
gch.recGcLock == 0:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
when withRealtime:
|
when withRealtime:
|
||||||
proc toNano(x: int): TNanos {.inline.} =
|
proc toNano(x: int): Nanos {.inline.} =
|
||||||
result = x * 1000
|
result = x * 1000
|
||||||
|
|
||||||
proc GC_setMaxPause*(MaxPauseInUs: int) =
|
proc GC_setMaxPause*(MaxPauseInUs: int) =
|
||||||
gch.maxPause = MaxPauseInUs.toNano
|
gch.maxPause = MaxPauseInUs.toNano
|
||||||
|
|
||||||
proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
|
proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gch.maxPause = us.toNano
|
gch.maxPause = us.toNano
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||||
|
|
|
||||||
|
|
@ -26,49 +26,50 @@ when defined(memProfiler):
|
||||||
proc nimProfile(requestedSize: int)
|
proc nimProfile(requestedSize: int)
|
||||||
|
|
||||||
type
|
type
|
||||||
TWalkOp = enum
|
WalkOp = enum
|
||||||
waMarkGlobal, # we need to mark conservatively for global marker procs
|
waMarkGlobal, # we need to mark conservatively for global marker procs
|
||||||
# as these may refer to a global var and not to a thread
|
# as these may refer to a global var and not to a thread
|
||||||
# local
|
# local
|
||||||
waMarkPrecise # fast precise marking
|
waMarkPrecise # fast precise marking
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||||
# A ref type can have a finalizer that is called before the object's
|
# A ref type can have a finalizer that is called before the object's
|
||||||
# storage is freed.
|
# storage is freed.
|
||||||
|
|
||||||
TGlobalMarkerProc = proc () {.nimcall, benign.}
|
GlobalMarkerProc = proc () {.nimcall, benign.}
|
||||||
|
|
||||||
TGcStat = object
|
GcStat = object
|
||||||
collections: int # number of performed full collections
|
collections: int # number of performed full collections
|
||||||
maxThreshold: int # max threshold that has been set
|
maxThreshold: int # max threshold that has been set
|
||||||
maxStackSize: int # max stack size
|
maxStackSize: int # max stack size
|
||||||
freedObjects: int # max entries in cycle table
|
freedObjects: int # max entries in cycle table
|
||||||
|
|
||||||
TGcHeap = object # this contains the zero count and
|
GcHeap = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stackBottom: pointer
|
stackBottom: pointer
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
idGenerator: int
|
idGenerator: int
|
||||||
when withBitvectors:
|
when withBitvectors:
|
||||||
allocated, marked: TCellSet
|
allocated, marked: CellSet
|
||||||
tempStack: TCellSeq # temporary stack for recursion elimination
|
tempStack: CellSeq # temporary stack for recursion elimination
|
||||||
recGcLock: int # prevent recursion via finalizers; no thread lock
|
recGcLock: int # prevent recursion via finalizers; no thread lock
|
||||||
region: TMemRegion # garbage collected region
|
region: MemRegion # garbage collected region
|
||||||
stat: TGcStat
|
stat: GcStat
|
||||||
additionalRoots: TCellSeq # dummy roots for GC_ref/unref
|
additionalRoots: CellSeq # dummy roots for GC_ref/unref
|
||||||
|
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcStat: GcStat,
|
||||||
|
TGlobalMarkerProc: GlobalMarkerProc, TGcHeap, GcHeap].}
|
||||||
var
|
var
|
||||||
gch {.rtlThreadVar.}: TGcHeap
|
gch {.rtlThreadVar.}: GcHeap
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
instantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: GcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
releaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
|
|
@ -80,11 +81,11 @@ template gcAssert(cond: bool, msg: string) =
|
||||||
|
|
||||||
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
||||||
# convert object (=pointer to refcount) to pointer to userdata
|
# convert object (=pointer to refcount) to pointer to userdata
|
||||||
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
|
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
|
||||||
|
|
||||||
proc usrToCell(usr: pointer): PCell {.inline.} =
|
proc usrToCell(usr: pointer): PCell {.inline.} =
|
||||||
# convert pointer to userdata to object (=pointer to refcount)
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
|
||||||
|
|
||||||
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
||||||
result = ntfAcyclic notin c.typ.flags
|
result = ntfAcyclic notin c.typ.flags
|
||||||
|
|
@ -101,9 +102,9 @@ proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
|
||||||
|
|
||||||
var
|
var
|
||||||
globalMarkersLen: int
|
globalMarkersLen: int
|
||||||
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
|
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
|
||||||
|
|
||||||
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
|
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
|
||||||
if globalMarkersLen <= high(globalMarkers):
|
if globalMarkersLen <= high(globalMarkers):
|
||||||
globalMarkers[globalMarkersLen] = markerProc
|
globalMarkers[globalMarkersLen] = markerProc
|
||||||
inc globalMarkersLen
|
inc globalMarkersLen
|
||||||
|
|
@ -116,11 +117,11 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
|
||||||
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
||||||
|
|
||||||
# forward declarations:
|
# forward declarations:
|
||||||
proc collectCT(gch: var TGcHeap) {.benign.}
|
proc collectCT(gch: var GcHeap) {.benign.}
|
||||||
proc isOnStack*(p: pointer): bool {.noinline, benign.}
|
proc isOnStack*(p: pointer): bool {.noinline, benign.}
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
|
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
|
||||||
proc doOperation(p: pointer, op: TWalkOp) {.benign.}
|
proc doOperation(p: pointer, op: WalkOp) {.benign.}
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
||||||
# we need the prototype here for debugging purposes
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
|
@ -131,7 +132,7 @@ proc prepareDealloc(cell: PCell) =
|
||||||
# prevend recursive entering here by a lock.
|
# prevend recursive entering here by a lock.
|
||||||
# XXX: we should set the cell's children to nil!
|
# XXX: we should set the cell's children to nil!
|
||||||
inc(gch.recGcLock)
|
inc(gch.recGcLock)
|
||||||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
dec(gch.recGcLock)
|
dec(gch.recGcLock)
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerProc.} =
|
proc nimGCref(p: pointer) {.compilerProc.} =
|
||||||
|
|
@ -182,7 +183,7 @@ proc setupForeignThreadGc*() =
|
||||||
setStackBottom(addr(stackTop))
|
setStackBottom(addr(stackTop))
|
||||||
initGC()
|
initGC()
|
||||||
|
|
||||||
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
||||||
|
|
@ -194,7 +195,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
|
||||||
if m != nil: forAllSlotsAux(dest, m, op)
|
if m != nil: forAllSlotsAux(dest, m, op)
|
||||||
of nkNone: sysAssert(false, "forAllSlotsAux")
|
of nkNone: sysAssert(false, "forAllSlotsAux")
|
||||||
|
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
|
|
@ -208,7 +209,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
|
||||||
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
gcAssert(cell != nil, "forAllChildren: 1")
|
gcAssert(cell != nil, "forAllChildren: 1")
|
||||||
gcAssert(cell.typ != nil, "forAllChildren: 2")
|
gcAssert(cell.typ != nil, "forAllChildren: 2")
|
||||||
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
|
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
|
||||||
|
|
@ -228,12 +229,12 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||||
GenericSeqSize), cell.typ.base, op)
|
GenericSeqSize), cell.typ.base, op)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
# now it is buffered in the ZCT
|
# now it is buffered in the ZCT
|
||||||
res.typ = typ
|
res.typ = typ
|
||||||
|
|
@ -285,20 +286,20 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var ol = usrToCell(old)
|
var ol = usrToCell(old)
|
||||||
sysAssert(ol.typ != nil, "growObj: 1")
|
sysAssert(ol.typ != nil, "growObj: 1")
|
||||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
|
||||||
newsize-oldsize)
|
newsize-oldsize)
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
|
||||||
when false:
|
when false:
|
||||||
|
|
@ -306,7 +307,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
when withBitvectors: excl(gch.allocated, ol)
|
when withBitvectors: excl(gch.allocated, ol)
|
||||||
when reallyDealloc: rawDealloc(gch.region, ol)
|
when reallyDealloc: rawDealloc(gch.region, ol)
|
||||||
else:
|
else:
|
||||||
zeroMem(ol, sizeof(TCell))
|
zeroMem(ol, sizeof(Cell))
|
||||||
when withBitvectors: incl(gch.allocated, res)
|
when withBitvectors: incl(gch.allocated, res)
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
inc gch.idGenerator
|
inc gch.idGenerator
|
||||||
|
|
@ -322,7 +323,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||||
|
|
||||||
# ----------------- collector -----------------------------------------------
|
# ----------------- collector -----------------------------------------------
|
||||||
|
|
||||||
proc mark(gch: var TGcHeap, c: PCell) =
|
proc mark(gch: var GcHeap, c: PCell) =
|
||||||
when withBitvectors:
|
when withBitvectors:
|
||||||
incl(gch.marked, c)
|
incl(gch.marked, c)
|
||||||
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
||||||
|
|
@ -344,7 +345,7 @@ proc mark(gch: var TGcHeap, c: PCell) =
|
||||||
d.refCount = rcBlack
|
d.refCount = rcBlack
|
||||||
forAllChildren(d, waMarkPrecise)
|
forAllChildren(d, waMarkPrecise)
|
||||||
|
|
||||||
proc doOperation(p: pointer, op: TWalkOp) =
|
proc doOperation(p: pointer, op: WalkOp) =
|
||||||
if p == nil: return
|
if p == nil: return
|
||||||
var c: PCell = usrToCell(p)
|
var c: PCell = usrToCell(p)
|
||||||
gcAssert(c != nil, "doOperation: 1")
|
gcAssert(c != nil, "doOperation: 1")
|
||||||
|
|
@ -359,17 +360,17 @@ proc doOperation(p: pointer, op: TWalkOp) =
|
||||||
of waMarkPrecise: add(gch.tempStack, c)
|
of waMarkPrecise: add(gch.tempStack, c)
|
||||||
|
|
||||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||||
doOperation(d, TWalkOp(op))
|
doOperation(d, WalkOp(op))
|
||||||
|
|
||||||
proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
proc freeCyclicCell(gch: var GcHeap, c: PCell) =
|
||||||
inc gch.stat.freedObjects
|
inc gch.stat.freedObjects
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
when reallyDealloc: rawDealloc(gch.region, c)
|
when reallyDealloc: rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
gcAssert(c.typ != nil, "freeCyclicCell")
|
gcAssert(c.typ != nil, "freeCyclicCell")
|
||||||
zeroMem(c, sizeof(TCell))
|
zeroMem(c, sizeof(Cell))
|
||||||
|
|
||||||
proc sweep(gch: var TGcHeap) =
|
proc sweep(gch: var GcHeap) =
|
||||||
when withBitvectors:
|
when withBitvectors:
|
||||||
for c in gch.allocated.elementsExcept(gch.marked):
|
for c in gch.allocated.elementsExcept(gch.marked):
|
||||||
gch.allocated.excl(c)
|
gch.allocated.excl(c)
|
||||||
|
|
@ -391,12 +392,12 @@ when false:
|
||||||
writeStackTrace()
|
writeStackTrace()
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
proc markGlobals(gch: var TGcHeap) =
|
proc markGlobals(gch: var GcHeap) =
|
||||||
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
|
||||||
let d = gch.additionalRoots.d
|
let d = gch.additionalRoots.d
|
||||||
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
|
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
|
||||||
|
|
||||||
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||||
# the addresses are not as cells on the stack, so turn them to cells:
|
# the addresses are not as cells on the stack, so turn them to cells:
|
||||||
var cell = usrToCell(p)
|
var cell = usrToCell(p)
|
||||||
var c = cast[ByteAddress](cell)
|
var c = cast[ByteAddress](cell)
|
||||||
|
|
@ -446,7 +447,7 @@ when defined(sparc): # For SPARC architecture.
|
||||||
var x = cast[ByteAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
when defined(sparcv9):
|
when defined(sparcv9):
|
||||||
asm """"flushw \n" """
|
asm """"flushw \n" """
|
||||||
else:
|
else:
|
||||||
|
|
@ -479,10 +480,10 @@ elif stackIncreases:
|
||||||
|
|
||||||
var
|
var
|
||||||
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
|
||||||
# a little hack to get the size of a TJmpBuf in the generated C code
|
# a little hack to get the size of a JmpBuf in the generated C code
|
||||||
# in a platform independent way
|
# in a platform independent way
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
var registers: C_JmpBuf
|
var registers: C_JmpBuf
|
||||||
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
|
||||||
var max = cast[ByteAddress](gch.stackBottom)
|
var max = cast[ByteAddress](gch.stackBottom)
|
||||||
|
|
@ -505,7 +506,7 @@ else:
|
||||||
var x = cast[ByteAddress](p)
|
var x = cast[ByteAddress](p)
|
||||||
result = a <=% x and x <=% b
|
result = a <=% x and x <=% b
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
# We use a jmp_buf buffer that is in the C stack.
|
# We use a jmp_buf buffer that is in the C stack.
|
||||||
# Used to traverse the stack and registers assuming
|
# Used to traverse the stack and registers assuming
|
||||||
# that 'setjmp' will save registers in the C stack.
|
# that 'setjmp' will save registers in the C stack.
|
||||||
|
|
@ -543,7 +544,7 @@ else:
|
||||||
# end of non-portable code
|
# end of non-portable code
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc collectCTBody(gch: var TGcHeap) =
|
proc collectCTBody(gch: var GcHeap) =
|
||||||
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
markStackAndRegisters(gch)
|
markStackAndRegisters(gch)
|
||||||
|
|
@ -558,7 +559,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
proc collectCT(gch: var GcHeap) =
|
||||||
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
|
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@ else:
|
||||||
proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
|
proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
|
||||||
|
|
||||||
type
|
type
|
||||||
PSafePoint = ptr TSafePoint
|
PSafePoint = ptr SafePoint
|
||||||
TSafePoint {.compilerproc, final.} = object
|
SafePoint {.compilerproc, final.} = object
|
||||||
prev: PSafePoint # points to next safe point
|
prev: PSafePoint # points to next safe point
|
||||||
exc: ref Exception
|
exc: ref Exception
|
||||||
|
|
||||||
PCallFrame = ptr TCallFrame
|
PCallFrame = ptr CallFrame
|
||||||
TCallFrame {.importc, nodecl, final.} = object
|
CallFrame {.importc, nodecl, final.} = object
|
||||||
prev: PCallFrame
|
prev: PCallFrame
|
||||||
procname: cstring
|
procname: cstring
|
||||||
line: int # current line number
|
line: int # current line number
|
||||||
|
|
@ -33,6 +33,7 @@ type
|
||||||
lineNumber {.importc.}: int
|
lineNumber {.importc.}: int
|
||||||
message {.importc.}: cstring
|
message {.importc.}: cstring
|
||||||
stack {.importc.}: cstring
|
stack {.importc.}: cstring
|
||||||
|
{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].}
|
||||||
|
|
||||||
var
|
var
|
||||||
framePtr {.importc, nodecl, volatile.}: PCallFrame
|
framePtr {.importc, nodecl, volatile.}: PCallFrame
|
||||||
|
|
@ -60,12 +61,13 @@ proc getCurrentExceptionMsg*(): string =
|
||||||
|
|
||||||
proc auxWriteStackTrace(f: PCallFrame): string =
|
proc auxWriteStackTrace(f: PCallFrame): string =
|
||||||
type
|
type
|
||||||
TTempFrame = tuple[procname: cstring, line: int]
|
TempFrame = tuple[procname: cstring, line: int]
|
||||||
|
{.deprecated: [TTempFrame: TempFrame].}
|
||||||
var
|
var
|
||||||
it = f
|
it = f
|
||||||
i = 0
|
i = 0
|
||||||
total = 0
|
total = 0
|
||||||
tempFrames: array [0..63, TTempFrame]
|
tempFrames: array [0..63, TempFrame]
|
||||||
while it != nil and i <= high(tempFrames):
|
while it != nil and i <= high(tempFrames):
|
||||||
tempFrames[i].procname = it.procname
|
tempFrames[i].procname = it.procname
|
||||||
tempFrames[i].line = it.line
|
tempFrames[i].line = it.line
|
||||||
|
|
@ -260,17 +262,17 @@ proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
TDocument {.importc.} = object of RootObj
|
Document {.importc.} = object of RootObj
|
||||||
write: proc (text: cstring) {.nimcall.}
|
write: proc (text: cstring) {.nimcall.}
|
||||||
writeln: proc (text: cstring) {.nimcall.}
|
writeln: proc (text: cstring) {.nimcall.}
|
||||||
createAttribute: proc (identifier: cstring): ref TNode {.nimcall.}
|
createAttribute: proc (identifier: cstring): ref Node {.nimcall.}
|
||||||
createElement: proc (identifier: cstring): ref TNode {.nimcall.}
|
createElement: proc (identifier: cstring): ref Node {.nimcall.}
|
||||||
createTextNode: proc (identifier: cstring): ref TNode {.nimcall.}
|
createTextNode: proc (identifier: cstring): ref Node {.nimcall.}
|
||||||
getElementById: proc (id: cstring): ref TNode {.nimcall.}
|
getElementById: proc (id: cstring): ref Node {.nimcall.}
|
||||||
getElementsByName: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
getElementsByName: proc (name: cstring): seq[ref Node] {.nimcall.}
|
||||||
getElementsByTagName: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
getElementsByTagName: proc (name: cstring): seq[ref Node] {.nimcall.}
|
||||||
|
|
||||||
TNodeType* = enum
|
NodeType* = enum
|
||||||
ElementNode = 1,
|
ElementNode = 1,
|
||||||
AttributeNode,
|
AttributeNode,
|
||||||
TextNode,
|
TextNode,
|
||||||
|
|
@ -283,35 +285,36 @@ type
|
||||||
DocumentTypeNode,
|
DocumentTypeNode,
|
||||||
DocumentFragmentNode,
|
DocumentFragmentNode,
|
||||||
NotationNode
|
NotationNode
|
||||||
TNode* {.importc.} = object of RootObj
|
Node* {.importc.} = object of RootObj
|
||||||
attributes*: seq[ref TNode]
|
attributes*: seq[ref Node]
|
||||||
childNodes*: seq[ref TNode]
|
childNodes*: seq[ref Node]
|
||||||
data*: cstring
|
data*: cstring
|
||||||
firstChild*: ref TNode
|
firstChild*: ref Node
|
||||||
lastChild*: ref TNode
|
lastChild*: ref Node
|
||||||
nextSibling*: ref TNode
|
nextSibling*: ref Node
|
||||||
nodeName*: cstring
|
nodeName*: cstring
|
||||||
nodeType*: TNodeType
|
nodeType*: NodeType
|
||||||
nodeValue*: cstring
|
nodeValue*: cstring
|
||||||
parentNode*: ref TNode
|
parentNode*: ref Node
|
||||||
previousSibling*: ref TNode
|
previousSibling*: ref Node
|
||||||
appendChild*: proc (child: ref TNode) {.nimcall.}
|
appendChild*: proc (child: ref Node) {.nimcall.}
|
||||||
appendData*: proc (data: cstring) {.nimcall.}
|
appendData*: proc (data: cstring) {.nimcall.}
|
||||||
cloneNode*: proc (copyContent: bool) {.nimcall.}
|
cloneNode*: proc (copyContent: bool) {.nimcall.}
|
||||||
deleteData*: proc (start, len: int) {.nimcall.}
|
deleteData*: proc (start, len: int) {.nimcall.}
|
||||||
getAttribute*: proc (attr: cstring): cstring {.nimcall.}
|
getAttribute*: proc (attr: cstring): cstring {.nimcall.}
|
||||||
getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
|
getAttributeNode*: proc (attr: cstring): ref Node {.nimcall.}
|
||||||
getElementsByTagName*: proc (): seq[ref TNode] {.nimcall.}
|
getElementsByTagName*: proc (): seq[ref Node] {.nimcall.}
|
||||||
hasChildNodes*: proc (): bool {.nimcall.}
|
hasChildNodes*: proc (): bool {.nimcall.}
|
||||||
insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
|
insertBefore*: proc (newNode, before: ref Node) {.nimcall.}
|
||||||
insertData*: proc (position: int, data: cstring) {.nimcall.}
|
insertData*: proc (position: int, data: cstring) {.nimcall.}
|
||||||
removeAttribute*: proc (attr: cstring) {.nimcall.}
|
removeAttribute*: proc (attr: cstring) {.nimcall.}
|
||||||
removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
|
removeAttributeNode*: proc (attr: ref Node) {.nimcall.}
|
||||||
removeChild*: proc (child: ref TNode) {.nimcall.}
|
removeChild*: proc (child: ref Node) {.nimcall.}
|
||||||
replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
|
replaceChild*: proc (newNode, oldNode: ref Node) {.nimcall.}
|
||||||
replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
|
replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
|
||||||
setAttribute*: proc (name, value: cstring) {.nimcall.}
|
setAttribute*: proc (name, value: cstring) {.nimcall.}
|
||||||
setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
|
setAttributeNode*: proc (attr: ref Node) {.nimcall.}
|
||||||
|
{.deprecated: [TNode: Node, TNodeType: NodeType, TDocument: Document].}
|
||||||
|
|
||||||
when defined(kwin):
|
when defined(kwin):
|
||||||
proc rawEcho {.compilerproc, asmNoStackFrame.} =
|
proc rawEcho {.compilerproc, asmNoStackFrame.} =
|
||||||
|
|
@ -337,7 +340,7 @@ elif defined(nodejs):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
var
|
var
|
||||||
document {.importc, nodecl.}: ref TDocument
|
document {.importc, nodecl.}: ref Document
|
||||||
|
|
||||||
proc ewriteln(x: cstring) =
|
proc ewriteln(x: cstring) =
|
||||||
var node = document.getElementsByTagName("body")[0]
|
var node = document.getElementsByTagName("body")[0]
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,10 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
PPointer = ptr pointer
|
PPointer = ptr pointer
|
||||||
TByteArray = array[0..1000_0000, byte]
|
ByteArray = array[0..1000_0000, byte]
|
||||||
PByte = ptr TByteArray
|
PByte = ptr ByteArray
|
||||||
PString = ptr string
|
PString = ptr string
|
||||||
|
{.deprecated: [TByteArray: ByteArray].}
|
||||||
|
|
||||||
# Page size of the system; in most cases 4096 bytes. For exotic OS or
|
# Page size of the system; in most cases 4096 bytes. For exotic OS or
|
||||||
# CPU this needs to be changed:
|
# CPU this needs to be changed:
|
||||||
|
|
@ -180,16 +181,17 @@ when defined(boehmgc):
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
type
|
type
|
||||||
TMemRegion = object {.final, pure.}
|
MemRegion = object {.final, pure.}
|
||||||
|
{.deprecated: [TMemRegion: MemRegion].}
|
||||||
|
|
||||||
proc alloc(r: var TMemRegion, size: int): pointer =
|
proc alloc(r: var MemRegion, size: int): pointer =
|
||||||
result = boehmAlloc(size)
|
result = boehmAlloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc alloc0(r: var TMemRegion, size: int): pointer =
|
proc alloc0(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
|
proc dealloc(r: var MemRegion, p: pointer) = boehmDealloc(p)
|
||||||
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.inline.} = discard
|
proc deallocOsPages() {.inline.} = discard
|
||||||
|
|
||||||
include "system/cellsets"
|
include "system/cellsets"
|
||||||
|
|
@ -257,14 +259,15 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
type
|
type
|
||||||
TMemRegion = object {.final, pure.}
|
MemRegion = object {.final, pure.}
|
||||||
|
{.deprecated: [TMemRegion: MemRegion].}
|
||||||
|
|
||||||
proc alloc(r: var TMemRegion, size: int): pointer =
|
proc alloc(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
proc alloc0(r: var TMemRegion, size: int): pointer =
|
proc alloc0(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc0(size)
|
result = alloc0(size)
|
||||||
proc dealloc(r: var TMemRegion, p: pointer) = dealloc(p)
|
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||||
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.inline.} = discard
|
proc deallocOsPages() {.inline.} = discard
|
||||||
|
|
||||||
elif defined(nogc):
|
elif defined(nogc):
|
||||||
|
|
@ -313,7 +316,7 @@ elif defined(nogc):
|
||||||
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
var allocator {.rtlThreadVar.}: TMemRegion
|
var allocator {.rtlThreadVar.}: MemRegion
|
||||||
instantiateForRegion(allocator)
|
instantiateForRegion(allocator)
|
||||||
|
|
||||||
include "system/cellsets"
|
include "system/cellsets"
|
||||||
|
|
@ -323,7 +326,7 @@ else:
|
||||||
|
|
||||||
include "system/cellsets"
|
include "system/cellsets"
|
||||||
when not leakDetector:
|
when not leakDetector:
|
||||||
sysAssert(sizeof(TCell) == sizeof(TFreeCell), "sizeof TFreeCell")
|
sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell")
|
||||||
when compileOption("gc", "v2"):
|
when compileOption("gc", "v2"):
|
||||||
include "system/gc2"
|
include "system/gc2"
|
||||||
elif defined(gcMarkAndSweep):
|
elif defined(gcMarkAndSweep):
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,11 @@ const
|
||||||
MaxTraceLen = 20 # tracking the last 20 calls is enough
|
MaxTraceLen = 20 # tracking the last 20 calls is enough
|
||||||
|
|
||||||
type
|
type
|
||||||
TStackTrace* = array [0..MaxTraceLen-1, cstring]
|
StackTrace* = array [0..MaxTraceLen-1, cstring]
|
||||||
TProfilerHook* = proc (st: TStackTrace) {.nimcall.}
|
ProfilerHook* = proc (st: StackTrace) {.nimcall.}
|
||||||
|
{.deprecated: [TStackTrace: StackTrace, TProfilerHook: ProfilerHook].}
|
||||||
|
|
||||||
proc captureStackTrace(f: PFrame, st: var TStackTrace) =
|
proc captureStackTrace(f: PFrame, st: var StackTrace) =
|
||||||
const
|
const
|
||||||
firstCalls = 5
|
firstCalls = 5
|
||||||
var
|
var
|
||||||
|
|
@ -51,14 +52,15 @@ proc captureStackTrace(f: PFrame, st: var TStackTrace) =
|
||||||
|
|
||||||
when defined(memProfiler):
|
when defined(memProfiler):
|
||||||
type
|
type
|
||||||
TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall, benign.}
|
MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, benign.}
|
||||||
|
{.deprecated: [TMemProfilerHook: MemProfilerHook].}
|
||||||
var
|
var
|
||||||
profilerHook*: TMemProfilerHook
|
profilerHook*: MemProfilerHook
|
||||||
## set this variable to provide a procedure that implements a profiler in
|
## set this variable to provide a procedure that implements a profiler in
|
||||||
## user space. See the `nimprof` module for a reference implementation.
|
## user space. See the `nimprof` module for a reference implementation.
|
||||||
|
|
||||||
proc callProfilerHook(hook: TMemProfilerHook, requestedSize: int) =
|
proc callProfilerHook(hook: MemProfilerHook, requestedSize: int) =
|
||||||
var st: TStackTrace
|
var st: StackTrace
|
||||||
captureStackTrace(framePtr, st)
|
captureStackTrace(framePtr, st)
|
||||||
hook(st, requestedSize)
|
hook(st, requestedSize)
|
||||||
|
|
||||||
|
|
@ -70,15 +72,15 @@ else:
|
||||||
SamplingInterval = 50_000
|
SamplingInterval = 50_000
|
||||||
# set this to change the default sampling interval
|
# set this to change the default sampling interval
|
||||||
var
|
var
|
||||||
profilerHook*: TProfilerHook
|
profilerHook*: ProfilerHook
|
||||||
## set this variable to provide a procedure that implements a profiler in
|
## set this variable to provide a procedure that implements a profiler in
|
||||||
## user space. See the `nimprof` module for a reference implementation.
|
## user space. See the `nimprof` module for a reference implementation.
|
||||||
gTicker {.threadvar.}: int
|
gTicker {.threadvar.}: int
|
||||||
|
|
||||||
proc callProfilerHook(hook: TProfilerHook) {.noinline.} =
|
proc callProfilerHook(hook: ProfilerHook) {.noinline.} =
|
||||||
# 'noinline' so that 'nimProfile' does not perform the stack allocation
|
# 'noinline' so that 'nimProfile' does not perform the stack allocation
|
||||||
# in the common case.
|
# in the common case.
|
||||||
var st: TStackTrace
|
var st: StackTrace
|
||||||
captureStackTrace(framePtr, st)
|
captureStackTrace(framePtr, st)
|
||||||
hook(st)
|
hook(st)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,38 +121,39 @@ proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
|
||||||
reprSetAux(result, p, typ)
|
reprSetAux(result, p, typ)
|
||||||
|
|
||||||
type
|
type
|
||||||
TReprClosure {.final.} = object # we cannot use a global variable here
|
ReprClosure {.final.} = object # we cannot use a global variable here
|
||||||
# as this wouldn't be thread-safe
|
# as this wouldn't be thread-safe
|
||||||
when declared(TCellSet):
|
when declared(CellSet):
|
||||||
marked: TCellSet
|
marked: CellSet
|
||||||
recdepth: int # do not recurse endlessly
|
recdepth: int # do not recurse endlessly
|
||||||
indent: int # indentation
|
indent: int # indentation
|
||||||
|
{.deprecated: [TReprClosure: ReprClosure].}
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc initReprClosure(cl: var TReprClosure) =
|
proc initReprClosure(cl: var ReprClosure) =
|
||||||
# Important: cellsets does not lock the heap when doing allocations! We
|
# Important: cellsets does not lock the heap when doing allocations! We
|
||||||
# have to do it here ...
|
# have to do it here ...
|
||||||
when hasThreadSupport and hasSharedHeap and declared(heapLock):
|
when hasThreadSupport and hasSharedHeap and declared(heapLock):
|
||||||
AcquireSys(HeapLock)
|
AcquireSys(HeapLock)
|
||||||
when declared(TCellSet):
|
when declared(CellSet):
|
||||||
init(cl.marked)
|
init(cl.marked)
|
||||||
cl.recdepth = -1 # default is to display everything!
|
cl.recdepth = -1 # default is to display everything!
|
||||||
cl.indent = 0
|
cl.indent = 0
|
||||||
|
|
||||||
proc deinitReprClosure(cl: var TReprClosure) =
|
proc deinitReprClosure(cl: var ReprClosure) =
|
||||||
when declared(TCellSet): deinit(cl.marked)
|
when declared(CellSet): deinit(cl.marked)
|
||||||
when hasThreadSupport and hasSharedHeap and declared(heapLock):
|
when hasThreadSupport and hasSharedHeap and declared(heapLock):
|
||||||
ReleaseSys(HeapLock)
|
ReleaseSys(HeapLock)
|
||||||
|
|
||||||
proc reprBreak(result: var string, cl: TReprClosure) =
|
proc reprBreak(result: var string, cl: ReprClosure) =
|
||||||
add result, "\n"
|
add result, "\n"
|
||||||
for i in 0..cl.indent-1: add result, ' '
|
for i in 0..cl.indent-1: add result, ' '
|
||||||
|
|
||||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) {.benign.}
|
cl: var ReprClosure) {.benign.}
|
||||||
|
|
||||||
proc reprArray(result: var string, p: pointer, typ: PNimType,
|
proc reprArray(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) =
|
cl: var ReprClosure) =
|
||||||
add result, "["
|
add result, "["
|
||||||
var bs = typ.base.size
|
var bs = typ.base.size
|
||||||
for i in 0..typ.size div bs - 1:
|
for i in 0..typ.size div bs - 1:
|
||||||
|
|
@ -161,7 +162,7 @@ when not defined(useNimRtl):
|
||||||
add result, "]"
|
add result, "]"
|
||||||
|
|
||||||
proc reprSequence(result: var string, p: pointer, typ: PNimType,
|
proc reprSequence(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) =
|
cl: var ReprClosure) =
|
||||||
if p == nil:
|
if p == nil:
|
||||||
add result, "nil"
|
add result, "nil"
|
||||||
return
|
return
|
||||||
|
|
@ -174,7 +175,7 @@ when not defined(useNimRtl):
|
||||||
add result, "]"
|
add result, "]"
|
||||||
|
|
||||||
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
||||||
cl: var TReprClosure) {.benign.} =
|
cl: var ReprClosure) {.benign.} =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkNone: sysAssert(false, "reprRecordAux")
|
of nkNone: sysAssert(false, "reprRecordAux")
|
||||||
of nkSlot:
|
of nkSlot:
|
||||||
|
|
@ -191,7 +192,7 @@ when not defined(useNimRtl):
|
||||||
if m != nil: reprRecordAux(result, p, m, cl)
|
if m != nil: reprRecordAux(result, p, m, cl)
|
||||||
|
|
||||||
proc reprRecord(result: var string, p: pointer, typ: PNimType,
|
proc reprRecord(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) =
|
cl: var ReprClosure) =
|
||||||
add result, "["
|
add result, "["
|
||||||
let oldLen = result.len
|
let oldLen = result.len
|
||||||
reprRecordAux(result, p, typ.node, cl)
|
reprRecordAux(result, p, typ.node, cl)
|
||||||
|
|
@ -201,9 +202,9 @@ when not defined(useNimRtl):
|
||||||
add result, "]"
|
add result, "]"
|
||||||
|
|
||||||
proc reprRef(result: var string, p: pointer, typ: PNimType,
|
proc reprRef(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) =
|
cl: var ReprClosure) =
|
||||||
# we know that p is not nil here:
|
# we know that p is not nil here:
|
||||||
when declared(TCellSet):
|
when declared(CellSet):
|
||||||
when defined(boehmGC) or defined(nogc):
|
when defined(boehmGC) or defined(nogc):
|
||||||
var cell = cast[PCell](p)
|
var cell = cast[PCell](p)
|
||||||
else:
|
else:
|
||||||
|
|
@ -216,7 +217,7 @@ when not defined(useNimRtl):
|
||||||
reprAux(result, p, typ.base, cl)
|
reprAux(result, p, typ.base, cl)
|
||||||
|
|
||||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||||
cl: var TReprClosure) =
|
cl: var ReprClosure) =
|
||||||
if cl.recdepth == 0:
|
if cl.recdepth == 0:
|
||||||
add result, "..."
|
add result, "..."
|
||||||
return
|
return
|
||||||
|
|
@ -261,7 +262,7 @@ when not defined(useNimRtl):
|
||||||
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
|
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
|
||||||
compilerRtl.} =
|
compilerRtl.} =
|
||||||
var
|
var
|
||||||
cl: TReprClosure
|
cl: ReprClosure
|
||||||
initReprClosure(cl)
|
initReprClosure(cl)
|
||||||
result = "["
|
result = "["
|
||||||
var bs = elemtyp.size
|
var bs = elemtyp.size
|
||||||
|
|
@ -274,7 +275,7 @@ proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc reprAny(p: pointer, typ: PNimType): string =
|
proc reprAny(p: pointer, typ: PNimType): string =
|
||||||
var
|
var
|
||||||
cl: TReprClosure
|
cl: ReprClosure
|
||||||
initReprClosure(cl)
|
initReprClosure(cl)
|
||||||
result = ""
|
result = ""
|
||||||
if typ.kind in {tyObject, tyTuple, tyArray, tyArrayConstr, tySet}:
|
if typ.kind in {tyObject, tyTuple, tyArray, tyArrayConstr, tySet}:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
# set handling
|
# set handling
|
||||||
|
|
||||||
type
|
type
|
||||||
TNimSet = array [0..4*2048-1, uint8]
|
NimSet = array [0..4*2048-1, uint8]
|
||||||
|
{.deprecated: [TNimSet: NimSet].}
|
||||||
|
|
||||||
proc countBits32(n: int32): int {.compilerproc.} =
|
proc countBits32(n: int32): int {.compilerproc.} =
|
||||||
var v = n
|
var v = n
|
||||||
|
|
@ -22,7 +23,7 @@ proc countBits64(n: int64): int {.compilerproc.} =
|
||||||
result = countBits32(toU32(n and 0xffff'i64)) +
|
result = countBits32(toU32(n and 0xffff'i64)) +
|
||||||
countBits32(toU32(n shr 16'i64))
|
countBits32(toU32(n shr 16'i64))
|
||||||
|
|
||||||
proc cardSet(s: TNimSet, len: int): int {.compilerproc.} =
|
proc cardSet(s: NimSet, len: int): int {.compilerproc.} =
|
||||||
result = 0
|
result = 0
|
||||||
for i in countup(0, len-1):
|
for i in countup(0, len-1):
|
||||||
inc(result, countBits32(int32(s[i])))
|
inc(result, countBits32(int32(s[i])))
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
type
|
type
|
||||||
THandle = int
|
Handle = int
|
||||||
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
|
SysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
|
||||||
DebugInfo: pointer
|
DebugInfo: pointer
|
||||||
LockCount: int32
|
LockCount: int32
|
||||||
RecursionCount: int32
|
RecursionCount: int32
|
||||||
|
|
@ -20,85 +20,87 @@ when defined(Windows):
|
||||||
LockSemaphore: int
|
LockSemaphore: int
|
||||||
Reserved: int32
|
Reserved: int32
|
||||||
|
|
||||||
TSysCond = THandle
|
SysCond = Handle
|
||||||
|
|
||||||
|
{.deprecated: [THandle: Handle, TSysLock: SysLock, TSysCond: SysCond].}
|
||||||
|
|
||||||
proc initSysLock(L: var TSysLock) {.stdcall, noSideEffect,
|
proc initSysLock(L: var SysLock) {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "InitializeCriticalSection".}
|
dynlib: "kernel32", importc: "InitializeCriticalSection".}
|
||||||
## Initializes the lock `L`.
|
## Initializes the lock `L`.
|
||||||
|
|
||||||
proc tryAcquireSysAux(L: var TSysLock): int32 {.stdcall, noSideEffect,
|
proc tryAcquireSysAux(L: var SysLock): int32 {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
|
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
|
||||||
## Tries to acquire the lock `L`.
|
## Tries to acquire the lock `L`.
|
||||||
|
|
||||||
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
|
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
|
||||||
result = tryAcquireSysAux(L) != 0'i32
|
result = tryAcquireSysAux(L) != 0'i32
|
||||||
|
|
||||||
proc acquireSys(L: var TSysLock) {.stdcall, noSideEffect,
|
proc acquireSys(L: var SysLock) {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "EnterCriticalSection".}
|
dynlib: "kernel32", importc: "EnterCriticalSection".}
|
||||||
## Acquires the lock `L`.
|
## Acquires the lock `L`.
|
||||||
|
|
||||||
proc releaseSys(L: var TSysLock) {.stdcall, noSideEffect,
|
proc releaseSys(L: var SysLock) {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "LeaveCriticalSection".}
|
dynlib: "kernel32", importc: "LeaveCriticalSection".}
|
||||||
## Releases the lock `L`.
|
## Releases the lock `L`.
|
||||||
|
|
||||||
proc deinitSys(L: var TSysLock) {.stdcall, noSideEffect,
|
proc deinitSys(L: var SysLock) {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "DeleteCriticalSection".}
|
dynlib: "kernel32", importc: "DeleteCriticalSection".}
|
||||||
|
|
||||||
proc createEvent(lpEventAttributes: pointer,
|
proc createEvent(lpEventAttributes: pointer,
|
||||||
bManualReset, bInitialState: int32,
|
bManualReset, bInitialState: int32,
|
||||||
lpName: cstring): TSysCond {.stdcall, noSideEffect,
|
lpName: cstring): SysCond {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "CreateEventA".}
|
dynlib: "kernel32", importc: "CreateEventA".}
|
||||||
|
|
||||||
proc closeHandle(hObject: THandle) {.stdcall, noSideEffect,
|
proc closeHandle(hObject: Handle) {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "CloseHandle".}
|
dynlib: "kernel32", importc: "CloseHandle".}
|
||||||
proc waitForSingleObject(hHandle: THandle, dwMilliseconds: int32): int32 {.
|
proc waitForSingleObject(hHandle: Handle, dwMilliseconds: int32): int32 {.
|
||||||
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.}
|
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.}
|
||||||
|
|
||||||
proc signalSysCond(hEvent: TSysCond) {.stdcall, noSideEffect,
|
proc signalSysCond(hEvent: SysCond) {.stdcall, noSideEffect,
|
||||||
dynlib: "kernel32", importc: "SetEvent".}
|
dynlib: "kernel32", importc: "SetEvent".}
|
||||||
|
|
||||||
proc initSysCond(cond: var TSysCond) {.inline.} =
|
proc initSysCond(cond: var SysCond) {.inline.} =
|
||||||
cond = createEvent(nil, 0'i32, 0'i32, nil)
|
cond = createEvent(nil, 0'i32, 0'i32, nil)
|
||||||
proc deinitSysCond(cond: var TSysCond) {.inline.} =
|
proc deinitSysCond(cond: var SysCond) {.inline.} =
|
||||||
closeHandle(cond)
|
closeHandle(cond)
|
||||||
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) =
|
proc waitSysCond(cond: var SysCond, lock: var SysLock) =
|
||||||
releaseSys(lock)
|
releaseSys(lock)
|
||||||
discard waitForSingleObject(cond, -1'i32)
|
discard waitForSingleObject(cond, -1'i32)
|
||||||
acquireSys(lock)
|
acquireSys(lock)
|
||||||
|
|
||||||
proc waitSysCondWindows(cond: var TSysCond) =
|
proc waitSysCondWindows(cond: var SysCond) =
|
||||||
discard waitForSingleObject(cond, -1'i32)
|
discard waitForSingleObject(cond, -1'i32)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
type
|
type
|
||||||
TSysLock {.importc: "pthread_mutex_t", pure, final,
|
SysLock {.importc: "pthread_mutex_t", pure, final,
|
||||||
header: "<sys/types.h>".} = object
|
header: "<sys/types.h>".} = object
|
||||||
TSysCond {.importc: "pthread_cond_t", pure, final,
|
SysCond {.importc: "pthread_cond_t", pure, final,
|
||||||
header: "<sys/types.h>".} = object
|
header: "<sys/types.h>".} = object
|
||||||
|
|
||||||
proc initSysLock(L: var TSysLock, attr: pointer = nil) {.
|
proc initSysLock(L: var SysLock, attr: pointer = nil) {.
|
||||||
importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
|
||||||
|
|
||||||
proc acquireSys(L: var TSysLock) {.noSideEffect,
|
proc acquireSys(L: var SysLock) {.noSideEffect,
|
||||||
importc: "pthread_mutex_lock", header: "<pthread.h>".}
|
importc: "pthread_mutex_lock", header: "<pthread.h>".}
|
||||||
proc tryAcquireSysAux(L: var TSysLock): cint {.noSideEffect,
|
proc tryAcquireSysAux(L: var SysLock): cint {.noSideEffect,
|
||||||
importc: "pthread_mutex_trylock", header: "<pthread.h>".}
|
importc: "pthread_mutex_trylock", header: "<pthread.h>".}
|
||||||
|
|
||||||
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
|
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
|
||||||
result = tryAcquireSysAux(L) == 0'i32
|
result = tryAcquireSysAux(L) == 0'i32
|
||||||
|
|
||||||
proc releaseSys(L: var TSysLock) {.noSideEffect,
|
proc releaseSys(L: var SysLock) {.noSideEffect,
|
||||||
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
|
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
|
||||||
proc deinitSys(L: var TSysLock) {.noSideEffect,
|
proc deinitSys(L: var SysLock) {.noSideEffect,
|
||||||
importc: "pthread_mutex_destroy", header: "<pthread.h>".}
|
importc: "pthread_mutex_destroy", header: "<pthread.h>".}
|
||||||
|
|
||||||
proc initSysCond(cond: var TSysCond, cond_attr: pointer = nil) {.
|
proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {.
|
||||||
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
|
||||||
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) {.
|
proc waitSysCond(cond: var SysCond, lock: var SysLock) {.
|
||||||
importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
|
||||||
proc signalSysCond(cond: var TSysCond) {.
|
proc signalSysCond(cond: var SysCond) {.
|
||||||
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
|
||||||
|
|
||||||
proc deinitSysCond(cond: var TSysCond) {.noSideEffect,
|
proc deinitSysCond(cond: var SysCond) {.noSideEffect,
|
||||||
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
importc: "pthread_cond_destroy", header: "<pthread.h>".}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ when not declared(NimString):
|
||||||
|
|
||||||
type
|
type
|
||||||
CondVar = object
|
CondVar = object
|
||||||
c: TSysCond
|
c: SysCond
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
stupidLock: TSysLock
|
stupidLock: SysLock
|
||||||
counter: int
|
counter: int
|
||||||
|
|
||||||
proc createCondVar(): CondVar =
|
proc createCondVar(): CondVar =
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@
|
||||||
## import locks
|
## import locks
|
||||||
##
|
##
|
||||||
## var
|
## var
|
||||||
## thr: array [0..4, TThread[tuple[a,b: int]]]
|
## thr: array [0..4, Thread[tuple[a,b: int]]]
|
||||||
## L: TLock
|
## L: Lock
|
||||||
##
|
##
|
||||||
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
|
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
|
||||||
## for i in interval.a..interval.b:
|
## for i in interval.a..interval.b:
|
||||||
|
|
@ -51,40 +51,41 @@ const
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
type
|
type
|
||||||
TSysThread = THandle
|
SysThread = Handle
|
||||||
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
WinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
||||||
|
{.deprecated: [TSysThread: SysThread, TWinThreadProc: WinThreadProc].}
|
||||||
|
|
||||||
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
|
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
|
||||||
lpStartAddress: TWinThreadProc,
|
lpStartAddress: WinThreadProc,
|
||||||
lpParameter: pointer,
|
lpParameter: pointer,
|
||||||
dwCreationFlags: int32,
|
dwCreationFlags: int32,
|
||||||
lpThreadId: var int32): TSysThread {.
|
lpThreadId: var int32): SysThread {.
|
||||||
stdcall, dynlib: "kernel32", importc: "CreateThread".}
|
stdcall, dynlib: "kernel32", importc: "CreateThread".}
|
||||||
|
|
||||||
proc winSuspendThread(hThread: TSysThread): int32 {.
|
proc winSuspendThread(hThread: SysThread): int32 {.
|
||||||
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
|
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
|
||||||
|
|
||||||
proc winResumeThread(hThread: TSysThread): int32 {.
|
proc winResumeThread(hThread: SysThread): int32 {.
|
||||||
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
|
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
|
||||||
|
|
||||||
proc waitForMultipleObjects(nCount: int32,
|
proc waitForMultipleObjects(nCount: int32,
|
||||||
lpHandles: ptr TSysThread,
|
lpHandles: ptr SysThread,
|
||||||
bWaitAll: int32,
|
bWaitAll: int32,
|
||||||
dwMilliseconds: int32): int32 {.
|
dwMilliseconds: int32): int32 {.
|
||||||
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
||||||
|
|
||||||
proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
|
proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {.
|
||||||
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
|
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
|
||||||
|
|
||||||
type
|
type
|
||||||
TThreadVarSlot = distinct int32
|
ThreadVarSlot = distinct int32
|
||||||
|
|
||||||
when true:
|
when true:
|
||||||
proc threadVarAlloc(): TThreadVarSlot {.
|
proc threadVarAlloc(): ThreadVarSlot {.
|
||||||
importc: "TlsAlloc", stdcall, header: "<windows.h>".}
|
importc: "TlsAlloc", stdcall, header: "<windows.h>".}
|
||||||
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
|
||||||
importc: "TlsSetValue", stdcall, header: "<windows.h>".}
|
importc: "TlsSetValue", stdcall, header: "<windows.h>".}
|
||||||
proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
|
||||||
importc: "TlsGetValue", stdcall, header: "<windows.h>".}
|
importc: "TlsGetValue", stdcall, header: "<windows.h>".}
|
||||||
|
|
||||||
proc getLastError(): uint32 {.
|
proc getLastError(): uint32 {.
|
||||||
|
|
@ -92,16 +93,16 @@ when defined(windows):
|
||||||
proc setLastError(x: uint32) {.
|
proc setLastError(x: uint32) {.
|
||||||
importc: "SetLastError", stdcall, header: "<windows.h>".}
|
importc: "SetLastError", stdcall, header: "<windows.h>".}
|
||||||
|
|
||||||
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer =
|
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer =
|
||||||
let realLastError = getLastError()
|
let realLastError = getLastError()
|
||||||
result = tlsGetValue(dwTlsIndex)
|
result = tlsGetValue(dwTlsIndex)
|
||||||
setLastError(realLastError)
|
setLastError(realLastError)
|
||||||
else:
|
else:
|
||||||
proc threadVarAlloc(): TThreadVarSlot {.
|
proc threadVarAlloc(): ThreadVarSlot {.
|
||||||
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||||
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
|
||||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||||
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
|
||||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
@ -111,55 +112,58 @@ else:
|
||||||
{.passC: "-pthread".}
|
{.passC: "-pthread".}
|
||||||
|
|
||||||
type
|
type
|
||||||
TSysThread {.importc: "pthread_t", header: "<sys/types.h>",
|
SysThread {.importc: "pthread_t", header: "<sys/types.h>",
|
||||||
final, pure.} = object
|
final, pure.} = object
|
||||||
Tpthread_attr {.importc: "pthread_attr_t",
|
Pthread_attr {.importc: "pthread_attr_t",
|
||||||
header: "<sys/types.h>", final, pure.} = object
|
header: "<sys/types.h>", final, pure.} = object
|
||||||
|
|
||||||
Ttimespec {.importc: "struct timespec",
|
Timespec {.importc: "struct timespec",
|
||||||
header: "<time.h>", final, pure.} = object
|
header: "<time.h>", final, pure.} = object
|
||||||
tv_sec: int
|
tv_sec: int
|
||||||
tv_nsec: int
|
tv_nsec: int
|
||||||
|
{.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
|
||||||
|
Ttimespec: Timespec].}
|
||||||
|
|
||||||
proc pthread_attr_init(a1: var TPthread_attr) {.
|
proc pthread_attr_init(a1: var PthreadAttr) {.
|
||||||
importc, header: "<pthread.h>".}
|
importc, header: "<pthread.h>".}
|
||||||
proc pthread_attr_setstacksize(a1: var TPthread_attr, a2: int) {.
|
proc pthread_attr_setstacksize(a1: var PthreadAttr, a2: int) {.
|
||||||
importc, header: "<pthread.h>".}
|
importc, header: "<pthread.h>".}
|
||||||
|
|
||||||
proc pthread_create(a1: var TSysThread, a2: var TPthread_attr,
|
proc pthread_create(a1: var SysThread, a2: var PthreadAttr,
|
||||||
a3: proc (x: pointer): pointer {.noconv.},
|
a3: proc (x: pointer): pointer {.noconv.},
|
||||||
a4: pointer): cint {.importc: "pthread_create",
|
a4: pointer): cint {.importc: "pthread_create",
|
||||||
header: "<pthread.h>".}
|
header: "<pthread.h>".}
|
||||||
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
|
proc pthread_join(a1: SysThread, a2: ptr pointer): cint {.
|
||||||
importc, header: "<pthread.h>".}
|
importc, header: "<pthread.h>".}
|
||||||
|
|
||||||
proc pthread_cancel(a1: TSysThread): cint {.
|
proc pthread_cancel(a1: SysThread): cint {.
|
||||||
importc: "pthread_cancel", header: "<pthread.h>".}
|
importc: "pthread_cancel", header: "<pthread.h>".}
|
||||||
|
|
||||||
type
|
type
|
||||||
TThreadVarSlot {.importc: "pthread_key_t", pure, final,
|
ThreadVarSlot {.importc: "pthread_key_t", pure, final,
|
||||||
header: "<sys/types.h>".} = object
|
header: "<sys/types.h>".} = object
|
||||||
|
{.deprecated: [TThreadVarSlot: ThreadVarSlot].}
|
||||||
|
|
||||||
proc pthread_getspecific(a1: TThreadVarSlot): pointer {.
|
proc pthread_getspecific(a1: ThreadVarSlot): pointer {.
|
||||||
importc: "pthread_getspecific", header: "<pthread.h>".}
|
importc: "pthread_getspecific", header: "<pthread.h>".}
|
||||||
proc pthread_key_create(a1: ptr TThreadVarSlot,
|
proc pthread_key_create(a1: ptr ThreadVarSlot,
|
||||||
destruct: proc (x: pointer) {.noconv.}): int32 {.
|
destruct: proc (x: pointer) {.noconv.}): int32 {.
|
||||||
importc: "pthread_key_create", header: "<pthread.h>".}
|
importc: "pthread_key_create", header: "<pthread.h>".}
|
||||||
proc pthread_key_delete(a1: TThreadVarSlot): int32 {.
|
proc pthread_key_delete(a1: ThreadVarSlot): int32 {.
|
||||||
importc: "pthread_key_delete", header: "<pthread.h>".}
|
importc: "pthread_key_delete", header: "<pthread.h>".}
|
||||||
|
|
||||||
proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
|
proc pthread_setspecific(a1: ThreadVarSlot, a2: pointer): int32 {.
|
||||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||||
|
|
||||||
proc threadVarAlloc(): TThreadVarSlot {.inline.} =
|
proc threadVarAlloc(): ThreadVarSlot {.inline.} =
|
||||||
discard pthread_key_create(addr(result), nil)
|
discard pthread_key_create(addr(result), nil)
|
||||||
proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
|
proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} =
|
||||||
discard pthread_setspecific(s, value)
|
discard pthread_setspecific(s, value)
|
||||||
proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
|
proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} =
|
||||||
result = pthread_getspecific(s)
|
result = pthread_getspecific(s)
|
||||||
|
|
||||||
when useStackMaskHack:
|
when useStackMaskHack:
|
||||||
proc pthread_attr_setstack(attr: var TPthread_attr, stackaddr: pointer,
|
proc pthread_attr_setstack(attr: var PthreadAttr, stackaddr: pointer,
|
||||||
size: int): cint {.
|
size: int): cint {.
|
||||||
importc: "pthread_attr_setstack", header: "<pthread.h>".}
|
importc: "pthread_attr_setstack", header: "<pthread.h>".}
|
||||||
|
|
||||||
|
|
@ -175,13 +179,13 @@ when emulatedThreadVars:
|
||||||
# allocations are needed. Currently less than 7K are used on a 64bit machine.
|
# allocations are needed. Currently less than 7K are used on a 64bit machine.
|
||||||
# We use ``float`` for proper alignment:
|
# We use ``float`` for proper alignment:
|
||||||
type
|
type
|
||||||
TThreadLocalStorage = array [0..1_000, float]
|
ThreadLocalStorage = array [0..1_000, float]
|
||||||
|
|
||||||
PGcThread = ptr TGcThread
|
PGcThread = ptr GcThread
|
||||||
TGcThread {.pure, inheritable.} = object
|
GcThread {.pure, inheritable.} = object
|
||||||
sys: TSysThread
|
sys: SysThread
|
||||||
when emulatedThreadVars and not useStackMaskHack:
|
when emulatedThreadVars and not useStackMaskHack:
|
||||||
tls: TThreadLocalStorage
|
tls: ThreadLocalStorage
|
||||||
else:
|
else:
|
||||||
nil
|
nil
|
||||||
when hasSharedHeap:
|
when hasSharedHeap:
|
||||||
|
|
@ -190,15 +194,16 @@ type
|
||||||
stackSize: int
|
stackSize: int
|
||||||
else:
|
else:
|
||||||
nil
|
nil
|
||||||
|
{.deprecated: [TThreadLocalStorage: ThreadLocalStorage, TGcThread: GcThread].}
|
||||||
|
|
||||||
# XXX it'd be more efficient to not use a global variable for the
|
# XXX it'd be more efficient to not use a global variable for the
|
||||||
# thread storage slot, but to rely on the implementation to assign slot X
|
# thread storage slot, but to rely on the implementation to assign slot X
|
||||||
# for us... ;-)
|
# for us... ;-)
|
||||||
var globalsSlot: TThreadVarSlot
|
var globalsSlot: ThreadVarSlot
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
when not useStackMaskHack:
|
when not useStackMaskHack:
|
||||||
var mainThread: TGcThread
|
var mainThread: GcThread
|
||||||
|
|
||||||
proc initThreadVarsEmulation() {.compilerProc, inline.} =
|
proc initThreadVarsEmulation() {.compilerProc, inline.} =
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
|
|
@ -206,7 +211,7 @@ proc initThreadVarsEmulation() {.compilerProc, inline.} =
|
||||||
when declared(mainThread):
|
when declared(mainThread):
|
||||||
threadVarSetValue(globalsSlot, addr(mainThread))
|
threadVarSetValue(globalsSlot, addr(mainThread))
|
||||||
|
|
||||||
#const globalsSlot = TThreadVarSlot(0)
|
#const globalsSlot = ThreadVarSlot(0)
|
||||||
#sysAssert checkSlot.int == globalsSlot.int
|
#sysAssert checkSlot.int == globalsSlot.int
|
||||||
|
|
||||||
when emulatedThreadVars:
|
when emulatedThreadVars:
|
||||||
|
|
@ -228,7 +233,7 @@ when not defined(useNimRtl):
|
||||||
initGC()
|
initGC()
|
||||||
|
|
||||||
when emulatedThreadVars:
|
when emulatedThreadVars:
|
||||||
if nimThreadVarsSize() > sizeof(TThreadLocalStorage):
|
if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
|
||||||
echo "too large thread local storage size requested"
|
echo "too large thread local storage size requested"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
|
|
@ -269,26 +274,27 @@ when not defined(useNimRtl):
|
||||||
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
|
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
|
||||||
|
|
||||||
type
|
type
|
||||||
TThread* {.pure, final.}[TArg] =
|
Thread* {.pure, final.}[TArg] =
|
||||||
object of TGcThread ## Nim thread. A thread is a heavy object (~14K)
|
object of GcThread ## Nim thread. A thread is a heavy object (~14K)
|
||||||
## that **must not** be part of a message! Use
|
## that **must not** be part of a message! Use
|
||||||
## a ``TThreadId`` for that.
|
## a ``ThreadId`` for that.
|
||||||
when TArg is void:
|
when TArg is void:
|
||||||
dataFn: proc () {.nimcall, gcsafe.}
|
dataFn: proc () {.nimcall, gcsafe.}
|
||||||
else:
|
else:
|
||||||
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
|
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
|
||||||
data: TArg
|
data: TArg
|
||||||
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
|
ThreadId*[TArg] = ptr Thread[TArg] ## the current implementation uses
|
||||||
## a pointer as a thread ID.
|
## a pointer as a thread ID.
|
||||||
|
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
|
||||||
|
|
||||||
when not defined(boehmgc) and not hasSharedHeap:
|
when not defined(boehmgc) and not hasSharedHeap:
|
||||||
proc deallocOsPages()
|
proc deallocOsPages()
|
||||||
|
|
||||||
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||||
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
||||||
var t = cast[ptr TThread[TArg]](closure)
|
var t = cast[ptr Thread[TArg]](closure)
|
||||||
when useStackMaskHack:
|
when useStackMaskHack:
|
||||||
var tls: TThreadLocalStorage
|
var tls: ThreadLocalStorage
|
||||||
when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap:
|
when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap:
|
||||||
# init the GC for this thread:
|
# init the GC for this thread:
|
||||||
setStackBottom(addr(t))
|
setStackBottom(addr(t))
|
||||||
|
|
@ -319,35 +325,35 @@ else:
|
||||||
threadProcWrapperBody(closure)
|
threadProcWrapperBody(closure)
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
|
proc running*[TArg](t: Thread[TArg]): bool {.inline.} =
|
||||||
## returns true if `t` is running.
|
## returns true if `t` is running.
|
||||||
result = t.dataFn != nil
|
result = t.dataFn != nil
|
||||||
|
|
||||||
when hostOS == "windows":
|
when hostOS == "windows":
|
||||||
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
|
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||||
## waits for the thread `t` to finish.
|
## waits for the thread `t` to finish.
|
||||||
discard waitForSingleObject(t.sys, -1'i32)
|
discard waitForSingleObject(t.sys, -1'i32)
|
||||||
|
|
||||||
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
|
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
|
||||||
## waits for every thread in `t` to finish.
|
## waits for every thread in `t` to finish.
|
||||||
var a: array[0..255, TSysThread]
|
var a: array[0..255, SysThread]
|
||||||
sysAssert a.len >= t.len, "a.len >= t.len"
|
sysAssert a.len >= t.len, "a.len >= t.len"
|
||||||
for i in 0..t.high: a[i] = t[i].sys
|
for i in 0..t.high: a[i] = t[i].sys
|
||||||
discard waitForMultipleObjects(t.len.int32,
|
discard waitForMultipleObjects(t.len.int32,
|
||||||
cast[ptr TSysThread](addr(a)), 1, -1)
|
cast[ptr SysThread](addr(a)), 1, -1)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
|
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||||
## waits for the thread `t` to finish.
|
## waits for the thread `t` to finish.
|
||||||
discard pthread_join(t.sys, nil)
|
discard pthread_join(t.sys, nil)
|
||||||
|
|
||||||
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
|
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
|
||||||
## waits for every thread in `t` to finish.
|
## waits for every thread in `t` to finish.
|
||||||
for i in 0..t.high: joinThread(t[i])
|
for i in 0..t.high: joinThread(t[i])
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
# XXX a thread should really release its heap here somehow:
|
# XXX a thread should really release its heap here somehow:
|
||||||
proc destroyThread*[TArg](t: var TThread[TArg]) =
|
proc destroyThread*[TArg](t: var Thread[TArg]) =
|
||||||
## forces the thread `t` to terminate. This is potentially dangerous if
|
## forces the thread `t` to terminate. This is potentially dangerous if
|
||||||
## you don't have full control over `t` and its acquired resources.
|
## you don't have full control over `t` and its acquired resources.
|
||||||
when hostOS == "windows":
|
when hostOS == "windows":
|
||||||
|
|
@ -358,7 +364,7 @@ when false:
|
||||||
t.dataFn = nil
|
t.dataFn = nil
|
||||||
|
|
||||||
when hostOS == "windows":
|
when hostOS == "windows":
|
||||||
proc createThread*[TArg](t: var TThread[TArg],
|
proc createThread*[TArg](t: var Thread[TArg],
|
||||||
tp: proc (arg: TArg) {.thread.},
|
tp: proc (arg: TArg) {.thread.},
|
||||||
param: TArg) =
|
param: TArg) =
|
||||||
## creates a new thread `t` and starts its execution. Entry point is the
|
## creates a new thread `t` and starts its execution. Entry point is the
|
||||||
|
|
@ -373,7 +379,7 @@ when hostOS == "windows":
|
||||||
if t.sys <= 0:
|
if t.sys <= 0:
|
||||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||||
else:
|
else:
|
||||||
proc createThread*[TArg](t: var TThread[TArg],
|
proc createThread*[TArg](t: var Thread[TArg],
|
||||||
tp: proc (arg: TArg) {.thread.},
|
tp: proc (arg: TArg) {.thread.},
|
||||||
param: TArg) =
|
param: TArg) =
|
||||||
## creates a new thread `t` and starts its execution. Entry point is the
|
## creates a new thread `t` and starts its execution. Entry point is the
|
||||||
|
|
@ -382,29 +388,29 @@ else:
|
||||||
when TArg isnot void: t.data = param
|
when TArg isnot void: t.data = param
|
||||||
t.dataFn = tp
|
t.dataFn = tp
|
||||||
when hasSharedHeap: t.stackSize = ThreadStackSize
|
when hasSharedHeap: t.stackSize = ThreadStackSize
|
||||||
var a {.noinit.}: Tpthread_attr
|
var a {.noinit.}: PthreadAttr
|
||||||
pthread_attr_init(a)
|
pthread_attr_init(a)
|
||||||
pthread_attr_setstacksize(a, ThreadStackSize)
|
pthread_attr_setstacksize(a, ThreadStackSize)
|
||||||
if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
|
if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
|
||||||
raise newException(ResourceExhaustedError, "cannot create thread")
|
raise newException(ResourceExhaustedError, "cannot create thread")
|
||||||
|
|
||||||
proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
|
proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
|
||||||
## returns the thread ID of `t`.
|
## returns the thread ID of `t`.
|
||||||
result = addr(t)
|
result = addr(t)
|
||||||
|
|
||||||
proc myThreadId*[TArg](): TThreadId[TArg] =
|
proc myThreadId*[TArg](): ThreadId[TArg] =
|
||||||
## returns the thread ID of the thread that calls this proc. This is unsafe
|
## returns the thread ID of the thread that calls this proc. This is unsafe
|
||||||
## because the type ``TArg`` is not checked for consistency!
|
## because the type ``TArg`` is not checked for consistency!
|
||||||
result = cast[TThreadId[TArg]](threadVarGetValue(globalsSlot))
|
result = cast[ThreadId[TArg]](threadVarGetValue(globalsSlot))
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc mainThreadId*[TArg](): TThreadId[TArg] =
|
proc mainThreadId*[TArg](): ThreadId[TArg] =
|
||||||
## returns the thread ID of the main thread.
|
## returns the thread ID of the main thread.
|
||||||
result = cast[TThreadId[TArg]](addr(mainThread))
|
result = cast[ThreadId[TArg]](addr(mainThread))
|
||||||
|
|
||||||
when useStackMaskHack:
|
when useStackMaskHack:
|
||||||
proc runMain(tp: proc () {.thread.}) {.compilerproc.} =
|
proc runMain(tp: proc () {.thread.}) {.compilerproc.} =
|
||||||
var mainThread: TThread[pointer]
|
var mainThread: Thread[pointer]
|
||||||
createThread(mainThread, tp)
|
createThread(mainThread, tp)
|
||||||
joinThread(mainThread)
|
joinThread(mainThread)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,83 +11,86 @@
|
||||||
## `<https://github.com/jckarter/clay/blob/master/compiler/src/hirestimer.cpp>`_
|
## `<https://github.com/jckarter/clay/blob/master/compiler/src/hirestimer.cpp>`_
|
||||||
|
|
||||||
type
|
type
|
||||||
TTicks = distinct int64
|
Ticks = distinct int64
|
||||||
TNanos = int64
|
Nanos = int64
|
||||||
|
{.deprecated: [TTicks: Ticks, TNanos: Nanos].}
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
||||||
proc QueryPerformanceCounter(res: var TTicks) {.
|
proc QueryPerformanceCounter(res: var Ticks) {.
|
||||||
importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
|
importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
|
||||||
proc QueryPerformanceFrequency(res: var int64) {.
|
proc QueryPerformanceFrequency(res: var int64) {.
|
||||||
importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
|
importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
|
||||||
|
|
||||||
proc getTicks(): TTicks {.inline.} =
|
proc getTicks(): Ticks {.inline.} =
|
||||||
QueryPerformanceCounter(result)
|
QueryPerformanceCounter(result)
|
||||||
|
|
||||||
proc `-`(a, b: TTicks): TNanos =
|
proc `-`(a, b: Ticks): Nanos =
|
||||||
var frequency: int64
|
var frequency: int64
|
||||||
QueryPerformanceFrequency(frequency)
|
QueryPerformanceFrequency(frequency)
|
||||||
var performanceCounterRate = 1e+9'f64 / float64(frequency)
|
var performanceCounterRate = 1e+9'f64 / float64(frequency)
|
||||||
|
|
||||||
result = TNanos(float64(a.int64 - b.int64) * performanceCounterRate)
|
result = Nanos(float64(a.int64 - b.int64) * performanceCounterRate)
|
||||||
|
|
||||||
elif defined(macosx):
|
elif defined(macosx):
|
||||||
type
|
type
|
||||||
TMachTimebaseInfoData {.pure, final,
|
MachTimebaseInfoData {.pure, final,
|
||||||
importc: "mach_timebase_info_data_t",
|
importc: "mach_timebase_info_data_t",
|
||||||
header: "<mach/mach_time.h>".} = object
|
header: "<mach/mach_time.h>".} = object
|
||||||
numer, denom: int32
|
numer, denom: int32
|
||||||
|
{.deprecated: [TMachTimebaseInfoData: MachTimebaseInfoData].}
|
||||||
|
|
||||||
proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
|
proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
|
||||||
proc mach_timebase_info(info: var TMachTimebaseInfoData) {.importc,
|
proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc,
|
||||||
header: "<mach/mach_time.h>".}
|
header: "<mach/mach_time.h>".}
|
||||||
|
|
||||||
proc getTicks(): TTicks {.inline.} =
|
proc getTicks(): Ticks {.inline.} =
|
||||||
result = TTicks(mach_absolute_time())
|
result = Ticks(mach_absolute_time())
|
||||||
|
|
||||||
var timeBaseInfo: TMachTimebaseInfoData
|
var timeBaseInfo: MachTimebaseInfoData
|
||||||
mach_timebase_info(timeBaseInfo)
|
mach_timebase_info(timeBaseInfo)
|
||||||
|
|
||||||
proc `-`(a, b: TTicks): TNanos =
|
proc `-`(a, b: Ticks): Nanos =
|
||||||
result = (a.int64 - b.int64) * timeBaseInfo.numer div timeBaseInfo.denom
|
result = (a.int64 - b.int64) * timeBaseInfo.numer div timeBaseInfo.denom
|
||||||
|
|
||||||
elif defined(posixRealtime):
|
elif defined(posixRealtime):
|
||||||
type
|
type
|
||||||
TClockid {.importc: "clockid_t", header: "<time.h>", final.} = object
|
Clockid {.importc: "clockid_t", header: "<time.h>", final.} = object
|
||||||
|
|
||||||
TTimeSpec {.importc: "struct timespec", header: "<time.h>",
|
TimeSpec {.importc: "struct timespec", header: "<time.h>",
|
||||||
final, pure.} = object ## struct timespec
|
final, pure.} = object ## struct timespec
|
||||||
tv_sec: int ## Seconds.
|
tv_sec: int ## Seconds.
|
||||||
tv_nsec: int ## Nanoseconds.
|
tv_nsec: int ## Nanoseconds.
|
||||||
|
{.deprecated: [TClockid: Clickid, TTimeSpec: TimeSpec].}
|
||||||
|
|
||||||
var
|
var
|
||||||
CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: TClockid
|
CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
|
||||||
|
|
||||||
proc clock_gettime(clkId: TClockid, tp: var TTimespec) {.
|
proc clock_gettime(clkId: Clockid, tp: var Timespec) {.
|
||||||
importc: "clock_gettime", header: "<time.h>".}
|
importc: "clock_gettime", header: "<time.h>".}
|
||||||
|
|
||||||
proc getTicks(): TTicks =
|
proc getTicks(): Ticks =
|
||||||
var t: TTimespec
|
var t: Timespec
|
||||||
clock_gettime(CLOCK_REALTIME, t)
|
clock_gettime(CLOCK_REALTIME, t)
|
||||||
result = TTicks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
|
result = Ticks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
|
||||||
|
|
||||||
proc `-`(a, b: TTicks): TNanos {.borrow.}
|
proc `-`(a, b: Ticks): Nanos {.borrow.}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# fallback Posix implementation:
|
# fallback Posix implementation:
|
||||||
type
|
type
|
||||||
Ttimeval {.importc: "struct timeval", header: "<sys/select.h>",
|
Timeval {.importc: "struct timeval", header: "<sys/select.h>",
|
||||||
final, pure.} = object ## struct timeval
|
final, pure.} = object ## struct timeval
|
||||||
tv_sec: int ## Seconds.
|
tv_sec: int ## Seconds.
|
||||||
tv_usec: int ## Microseconds.
|
tv_usec: int ## Microseconds.
|
||||||
|
{.deprecated: [Ttimeval: Timeval].}
|
||||||
proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {.
|
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
|
||||||
importc: "gettimeofday", header: "<sys/time.h>".}
|
importc: "gettimeofday", header: "<sys/time.h>".}
|
||||||
|
|
||||||
proc getTicks(): TTicks =
|
proc getTicks(): Ticks =
|
||||||
var t: Ttimeval
|
var t: Timeval
|
||||||
posix_gettimeofday(t)
|
posix_gettimeofday(t)
|
||||||
result = TTicks(int64(t.tv_sec) * 1000_000_000'i64 +
|
result = Ticks(int64(t.tv_sec) * 1000_000_000'i64 +
|
||||||
int64(t.tv_usec) * 1000'i64)
|
int64(t.tv_usec) * 1000'i64)
|
||||||
|
|
||||||
proc `-`(a, b: TTicks): TNanos {.borrow.}
|
proc `-`(a, b: Ticks): Nanos {.borrow.}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ when not declared(NimString):
|
||||||
{.error: "You must not import this module explicitly".}
|
{.error: "You must not import this module explicitly".}
|
||||||
|
|
||||||
type
|
type
|
||||||
TUtf16Char* = distinct int16
|
Utf16Char* = distinct int16
|
||||||
WideCString* = ref array[0.. 1_000_000, TUtf16Char]
|
WideCString* = ref array[0.. 1_000_000, Utf16Char]
|
||||||
|
{.deprecated: [TUtf16Char: Utf16Char].}
|
||||||
|
|
||||||
proc len*(w: WideCString): int =
|
proc len*(w: WideCString): int =
|
||||||
## returns the length of a widestring. This traverses the whole string to
|
## returns the length of a widestring. This traverses the whole string to
|
||||||
|
|
@ -23,7 +24,7 @@ proc len*(w: WideCString): int =
|
||||||
while int16(w[result]) != 0'i16: inc result
|
while int16(w[result]) != 0'i16: inc result
|
||||||
|
|
||||||
const
|
const
|
||||||
UNI_REPLACEMENT_CHAR = TUtf16Char(0xFFFD'i16)
|
UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16)
|
||||||
UNI_MAX_BMP = 0x0000FFFF
|
UNI_MAX_BMP = 0x0000FFFF
|
||||||
UNI_MAX_UTF16 = 0x0010FFFF
|
UNI_MAX_UTF16 = 0x0010FFFF
|
||||||
UNI_MAX_UTF32 = 0x7FFFFFFF
|
UNI_MAX_UTF32 = 0x7FFFFFFF
|
||||||
|
|
@ -89,16 +90,16 @@ proc newWideCString*(source: cstring, L: int): WideCString =
|
||||||
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
|
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
|
||||||
result[d] = UNI_REPLACEMENT_CHAR
|
result[d] = UNI_REPLACEMENT_CHAR
|
||||||
else:
|
else:
|
||||||
result[d] = TUtf16Char(toU16(ch))
|
result[d] = Utf16Char(toU16(ch))
|
||||||
elif ch >% UNI_MAX_UTF16:
|
elif ch >% UNI_MAX_UTF16:
|
||||||
result[d] = UNI_REPLACEMENT_CHAR
|
result[d] = UNI_REPLACEMENT_CHAR
|
||||||
else:
|
else:
|
||||||
let ch = ch -% halfBase
|
let ch = ch -% halfBase
|
||||||
result[d] = TUtf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
|
result[d] = Utf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
|
||||||
inc d
|
inc d
|
||||||
result[d] = TUtf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
|
result[d] = Utf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
|
||||||
inc d
|
inc d
|
||||||
result[d] = TUtf16Char(0'i16)
|
result[d] = Utf16Char(0'i16)
|
||||||
|
|
||||||
proc newWideCString*(s: cstring): WideCString =
|
proc newWideCString*(s: cstring): WideCString =
|
||||||
if s.isNil: return nil
|
if s.isNil: return nil
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue