146 lines
3.2 KiB
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 |