# 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