nondescript/src/ndspkg/gc.nim

146 lines
3.2 KiB
Nim

# marking for mark'n'sweep
import types/ndstack
import types/ndobject
import types/value
import types/ndstring
import types/hashtable
import types/closure
import types/ndlist
import memory
import config
import strformat
import strutils
import pointerutils
# globals
var
stack*: Stack[NdValue] = newStack[NdValue](256)
globals*: Table[NdValue, NdValue]
openUpvalues*: Upvalue[NdValue] = nil
var grayObjects: seq[ptr NdObject]
proc markObject*(obj: ptr NdObject) =
if obj.isMarked:
return
when debugGC:
let niceAddr = cast[uint](obj).toHex()
echo &"Marking object {niceAddr}."
obj.isMarked = true
grayObjects.add(obj)
proc markValue*(val: NdValue) =
if not val.isObject():
return
let obj: ptr NdObject = val.asObject()
obj.markObject()
proc markRoots =
var slot = 0
var stacklen = stack.len()
while slot < stacklen:
stack.getIndex(slot).markValue()
slot.inc
cast[NdTable[NdValue, NdValue]](globals.addr).markObject()
var upvalue = openUpvalues
while upvalue != nil:
upvalue.markObject()
upvalue = upvalue.next
proc blackenObject(obj: ptr NdObject) =
when debugGC:
let niceAddr = cast[uint](obj).toHex()
echo &"blackening {niceAddr}."
case obj.kind:
of noInvalid:
raise newException(Defect, "Somewhere an object with invalid object type was created.")
of noString:
discard
of noClosure:
let clos = cast[Closure[NdValue]](obj)
let count = clos.upvalueCount
var i = 0
while i < count:
let upval = clos.get(i)
if upval != nil:
markObject(upval)
i.inc
of noUpvalue:
let upval = cast[Upvalue[NdValue]](obj)
markValue(upval.location[])
of noList:
let list = cast[List[NdValue]](obj)
let count = list.getLength()
var i = 0
while i < count:
let elem = list.getIndex(i)
markValue(elem)
i.inc
of noTable:
let tbl = cast[NdTable[NdValue, NdValue]](obj)
for elem in tbl[].iterate():
markValue(elem)
proc traceReferences =
while grayObjects.len() > 0:
let obj = grayObjects.pop()
obj.blackenObject()
proc freeObj(obj: ptr NdObject) =
case obj.kind:
of noInvalid:
raise newException(Defect, "Somewhere an object with invalid object type was created.")
of noString:
let str = cast[NdString](obj)
str.free()
of noTable:
let tbl = cast[NdTable[NdValue, NdValue]](obj)
tbl.free()
of noClosure:
let clos = cast[Closure[NdValue]](obj)
clos.free()
of noList:
let list = cast[List[NdValue]](obj)
list.free()
of noUpvalue:
let upval = cast[Upvalue[NdValue]](obj)
upval.free()
proc sweep =
var previous: ptr NdObject = nil
var obj = objects
while obj != nil:
if obj.isMarked:
obj.isMarked = false
previous = obj
obj = obj.nextObj
else:
let unreached = obj
obj = obj.nextObj
if previous != nil:
previous.nextObj = obj
else:
objects = obj
unreached.freeObj()
proc icollectGarbage =
if not enableGC:
return
when debugGC:
echo "-- gc begin"
markRoots()
traceReferences()
tableRemoveWhite() # defined in types/ndstring
sweep()
when debugGC:
echo "-- gc end"
collectGarbage = icollectGarbage