Revert "BROKEN gc"

This reverts commit 0f9440dfb0.
This commit is contained in:
prod2 2022-02-14 07:15:11 +01:00
parent 0f9440dfb0
commit 545322bf96
13 changed files with 68 additions and 340 deletions

View File

@ -16,7 +16,7 @@ requires "nim >= 1.6.2"
task test, "run tests": task test, "run tests":
exec "nim c --gc:arc -d:release --skipProjCfg --skipParentCfg --out:bin/nds src/nds.nim" exec "nim c --gc:arc -d:release --skipProjCfg --skipParentCfg --out:bin/nds src/nds.nim"
exec "nim c --gc:arc -d:release --skipProjCfg --skipParentCfg -r tests/test.nim" exec "nim c --gc:arc -d:debug --skipProjCfg --skipParentCfg -r tests/test.nim"
exec "rm tests/test" exec "rm tests/test"
task debug, "build nds for debugging": task debug, "build nds for debugging":

View File

@ -1,8 +1,6 @@
import ../scanner import ../scanner
import ../chunk import ../chunk
import ../config import ../config
import ../types/ndobject
import ../memory
import types import types
import utils import utils
@ -15,8 +13,6 @@ import functions
import statement import statement
proc compile*(comp: Compiler) = proc compile*(comp: Compiler) =
let enableGCOld = enableGC
enableGC = false
comp.scanner = newScanner(comp.source) comp.scanner = newScanner(comp.source)
comp.writeChunk(0, opNil) comp.writeChunk(0, opNil)
# the starting stackIndex is 0, which points to this nil # the starting stackIndex is 0, which points to this nil
@ -29,4 +25,3 @@ proc compile*(comp: Compiler) =
when debugDumpChunk: when debugDumpChunk:
if not comp.hadError: if not comp.hadError:
comp.chunk.disassembleChunk() comp.chunk.disassembleChunk()
enableGC = enableGCOld

View File

@ -14,8 +14,6 @@ const assertionsVM* = defined(debug) or defined(release) # sanity checks in the
const boundsChecks* = defined(debug) or defined(release) const boundsChecks* = defined(debug) or defined(release)
const profileInstructions* = defined(ndsprofile) # if true, the time spent on every opcode is measured const profileInstructions* = defined(ndsprofile) # if true, the time spent on every opcode is measured
const debugClosures* = defined(debug) # specific closure debug switches const debugClosures* = defined(debug) # specific closure debug switches
const debugGC* = defined(debug) # debug GC
const stressGC* = true # garbage collect on every allocation
# choose a line editor for the repl # choose a line editor for the repl
const lineEditor = leRdstdin const lineEditor = leRdstdin

View File

@ -1,146 +0,0 @@
# 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

View File

@ -1,41 +0,0 @@
import config
import strutils
import strformat
var collectGarbage*: proc: void {.closure.}
var enableGC* = false
# set by the compiler/VM as needed
proc ndAlloc*(size: int): pointer =
when debugGC:
echo &"Allocating {$size} bytes."
when stressGC:
if enableGC:
collectGarbage()
alloc(size)
proc ndAlloc0*(size: int): pointer =
when debugGC:
echo &"Allocating and zeroing {$size} bytes."
when stressGC:
if enableGC:
collectGarbage()
alloc0(size)
proc ndRealloc*[T](source: ptr T, oldsize: int, newsize: int): ptr T =
when debugGC:
let niceAddr = cast[uint](source).toHex()
echo &"Reallocating {niceAddr} from size {$oldsize} to {$newsize}."
if newsize > oldsize:
when stressGC:
if enableGC:
collectGarbage()
discard
cast[ptr T](realloc(source, newsize))
proc ndDealloc*[T](mem: ptr T) =
when debugGC:
let niceAddr = cast[uint](mem).toHex()
echo &"Freeing {niceAddr}"
dealloc(mem)

View File

@ -1,33 +1,23 @@
import strformat import strformat
import strutils import strutils
import ndobject
import ../memory
type type
UpvalueObj[T] = object of NdObject UpvalueObj[T] = object
location*: ptr T location*: ptr T
next*: Upvalue[T] next*: Upvalue[T]
closed*: T closed*: T
Upvalue*[T] = ptr UpvalueObj[T] Upvalue*[T] = ptr UpvalueObj[T]
ClosureObj[T] = object of NdObject ClosureObj[T] = object
start: ptr uint8 start: ptr uint8
upvalueCount*: int upvalueCount*: int
upvalues: UncheckedArray[Upvalue[T]] upvalues: UncheckedArray[Upvalue[T]]
Closure*[T] = ptr ClosureObj[T] Closure*[T] = ptr ClosureObj[T]
proc free*[T](clos: Closure[T]) =
ndDealloc(clos)
proc free*[T](upval: Upvalue[T]) =
ndDealloc(upval)
proc newClosure*[T](start: ptr uint8, upvalueCount: int): Closure[T] = proc newClosure*[T](start: ptr uint8, upvalueCount: int): Closure[T] =
result = cast[Closure[T]](ndAlloc0(8 * upvalueCount + sizeof(ClosureObj[T]))) result = cast[Closure[T]](alloc0(8 * upvalueCount + sizeof(ClosureObj[T])))
result.kind = noClosure
result.newObject()
result.start = start result.start = start
result.upvalueCount = upvalueCount result.upvalueCount = upvalueCount
for i in 0 .. upvalueCount: for i in 0 .. upvalueCount:
@ -57,9 +47,7 @@ proc debugStr*[T](clos: Closure[T]): string =
result &= ")" result &= ")"
proc newUpvalue*[T](location: ptr T): Upvalue[T] = proc newUpvalue*[T](location: ptr T): Upvalue[T] =
result = cast[Upvalue[T]](ndAlloc0(sizeof(UpvalueObj[T]))) result = cast[Upvalue[T]](alloc0(sizeof(UpvalueObj[T])))
result.kind = noUpvalue
result.newObject()
result.location = location result.location = location
result.next = nil result.next = nil

View File

@ -1,8 +1,6 @@
# The hash table implementation for string interning and globals # The hash table implementation for string interning and globals
import bitops import bitops
import ndobject
import ../memory
const tableMaxLoad = 0.75 const tableMaxLoad = 0.75
const tableInitSize = 8 const tableInitSize = 8
@ -16,7 +14,7 @@ type
key: U key: U
value: V value: V
Table*[U, V] = object of NdObject Table*[U, V] = object
count: int count: int
cap: int cap: int
entries: ptr UncheckedArray[Entry[U, V]] entries: ptr UncheckedArray[Entry[U, V]]
@ -26,24 +24,16 @@ type
proc newTable*[U, V]: Table[U, V] = proc newTable*[U, V]: Table[U, V] =
result.cap = 0 result.cap = 0
result.count = 0 result.count = 0
result.kind = noTable
# not calling result.newObject()
proc newNdTable*[U, V]: NdTable[U, V] = proc newNdTable*[U, V]: NdTable[U, V] =
result = cast[NdTable[U, V]](ndAlloc(sizeof(Table[U, V]))) result = cast[NdTable[U, V]](alloc(sizeof(Table[U, V])))
result[].kind = noTable
result.newObject()
result[].cap = 0 result[].cap = 0
result[].count = 0 result[].count = 0
result[].entries = nil # must be set, because dealloc will be ran on it otherwise result[].entries = nil # must be set, because dealloc will be ran on it otherwise
proc free*[U, V](tbl: Table[U, V]) = proc free*[U, V](tbl: var Table[U, V]) =
if tbl.entries != nil: if tbl.entries != nil:
ndDealloc(tbl.entries) dealloc(tbl.entries)
proc free*[U, V](tbl: NdTable[U, V]) =
tbl[].free()
ndDealloc(tbl)
proc findEntry[U, V](entries: ptr UncheckedArray[Entry[U, V]], cap: int, key: U): ptr Entry[U, V] = proc findEntry[U, V](entries: ptr UncheckedArray[Entry[U, V]], cap: int, key: U): ptr Entry[U, V] =
mixin fnv1a, equal mixin fnv1a, equal
@ -70,7 +60,7 @@ proc grow[U, V](tbl: var Table[U, V]): int =
tableInitSize tableInitSize
proc adjustCapacity[U, V](tbl: var Table[U, V], newcap: int) = proc adjustCapacity[U, V](tbl: var Table[U, V], newcap: int) =
let entries: ptr UncheckedArray[Entry[U, V]] = cast[ptr UncheckedArray[Entry[U, V]]](ndAlloc0(newcap * sizeof(Entry[U, V]))) let entries: ptr UncheckedArray[Entry[U, V]] = cast[ptr UncheckedArray[Entry[U, V]]](alloc0(newcap * sizeof(Entry[U, V])))
tbl.count = 0 tbl.count = 0
if tbl.entries != nil: if tbl.entries != nil:
@ -83,7 +73,7 @@ proc adjustCapacity[U, V](tbl: var Table[U, V], newcap: int) =
dest[].entryStatus = esAlive dest[].entryStatus = esAlive
tbl.count.inc tbl.count.inc
ndDealloc(tbl.entries) dealloc(tbl.entries)
tbl.entries = entries tbl.entries = entries
tbl.cap = newcap tbl.cap = newcap
@ -151,14 +141,6 @@ proc tableDelete*[U, V](tbl: Table[U, V], key: U): bool =
proc getLength*[U, V](tbl: NdTable[U, V]): int = proc getLength*[U, V](tbl: NdTable[U, V]): int =
tbl.count.int tbl.count.int
iterator iterate*[T](tbl: Table[T, T]): T =
if tbl.entries != nil:
for i in countup(0, tbl.cap-1):
let entry = tbl.entries[i]
if entry.entryStatus == esAlive:
yield entry.key
yield entry.value
proc `$`*[U, V](tbl: NdTable[U, V], tagged: V): string = proc `$`*[U, V](tbl: NdTable[U, V], tagged: V): string =
if tbl[].count == 0: if tbl[].count == 0:
return "@{}" return "@{}"

View File

@ -1,6 +1,4 @@
import strformat import strformat
import ndobject
import ../memory
# configure ndlist here # configure ndlist here
import ../config import ../config
@ -13,41 +11,37 @@ const growthFactor = 2
const startCap = 8 const startCap = 8
type type
ListObj[T] = object of NdObject ListObj[T] = object
len: int len: int
cap: int cap: int
entries: ptr UncheckedArray[T] entries: ptr UncheckedArray[T]
List*[T] = ptr ListObj[T] List*[T] = ptr ListObj[T]
proc newList*[T](): List[T] = proc newList*[T](): List[T] =
result = cast[List[T]](ndAlloc(sizeof(ListObj[T]))) result = cast[List[T]](alloc(sizeof(ListObj[T])))
result.len = 0 result.len = 0
result.cap = 0 result.cap = 0
result.kind = noList
result.newObject()
proc newListCopymem*[T](start: ptr T, len: int): List[T] = proc newListCopymem*[T](start: ptr T, len: int): List[T] =
result = newList[T]() result = newList[T]()
result.len = len result.len = len
result.cap = len result.cap = len
result.entries = cast[ptr UncheckedArray[T]](ndAlloc(sizeof(T) * len)) result.entries = cast[ptr UncheckedArray[T]](alloc(sizeof(T) * len))
copyMem(result.entries, start, len * sizeof(T)) copyMem(result.entries, start, len * sizeof(T))
proc free*[T](list: List[T]) = proc free*[T](list: var List[T]) =
## dealloc's the list object ## dealloc's the list object
list.ndDealloc() list.dealloc()
proc grow[T](list: var List[T]) = proc grow[T](list: var List[T]) =
## growth the list's capacity ## growth the list's capacity
let oldcap = list.cap let newcap = if list.cap == 0: startCap else: list.cap * growthFactor
let oldsize = oldcap * sizeof(T)
let newcap = if oldcap == 0: startCap else: oldcap * growthFactor
let size = newcap * sizeof(T) let size = newcap * sizeof(T)
if oldcap == 0: if list.cap == 0:
list.entries = cast[ptr UncheckedArray[T]](size.ndAlloc()) list.entries = cast[ptr UncheckedArray[T]](size.alloc())
list.cap = newcap list.cap = newcap
else: else:
list.entries = cast[ptr UncheckedArray[T]](list.entries.ndRealloc(oldsize, size)) list.entries = cast[ptr UncheckedArray[T]](list.entries.realloc(size))
list.cap = newcap list.cap = newcap
proc add*[T](list: var List[T], item: T) = proc add*[T](list: var List[T], item: T) =

View File

@ -1,22 +0,0 @@
# generic object type
import ../config
type
NdObjectKind* = enum
noInvalid, noString, noClosure, noUpvalue, noList, noTable
NdObject* = object of RootObj
kind*: NdObjectKind
isMarked*: bool
nextObj*: ptr NdObject
var objects*: ptr NdObject
template newObject*(obj: ptr NdObject) =
when assertionsVM:
if obj.kind == noInvalid:
raise newException(Defect, "Somewhere an object with invalid object type was created.")
obj.nextObj = objects
objects = obj

View File

@ -1,16 +1,13 @@
import hashtable import hashtable
import ndobject
import ../memory
type type
NdStringObj* = object of NdObject NdString* = ptr object
len*: uint32 len*: uint32
hash*: uint32 hash*: uint32
chars*: UncheckedArray[char] chars*: UncheckedArray[char]
NdString* = ptr NdStringObj
proc free*(ndStr: NdString) = proc free*(ndStr: var NdString) =
ndDealloc(ndStr) dealloc(ndStr)
# hashes # hashes
@ -35,6 +32,7 @@ proc fnv1a*(str: char): int = # SHOULD RETURN THE SAME AS A 1 LENGTH STRING
hash *= 16777619 hash *= 16777619
return hash.int return hash.int
# equals # equals
proc equal*(left, right: NdString): bool = proc equal*(left, right: NdString): bool =
@ -42,13 +40,6 @@ proc equal*(left, right: NdString): bool =
var ndStrings = newTable[NdString, NdString]() var ndStrings = newTable[NdString, NdString]()
proc tableRemoveWhite* =
for elem in ndStrings.iterate():
if elem != nil:
# vals are nil, keys are not
if not elem.isMarked:
discard tableDelete(ndStrings, elem)
proc newString*(str: string): NdString = proc newString*(str: string): NdString =
let strlen = str.len() let strlen = str.len()
let hash = str.fnv1a() let hash = str.fnv1a()
@ -62,12 +53,10 @@ proc newString*(str: string): NdString =
if interned != nil: if interned != nil:
return interned return interned
let len = sizeof(NdStringObj) + strlen let len = 8 + strlen
result = cast[NdString](ndAlloc(len)) result = cast[NdString](alloc(len))
result.len = strlen.uint32 result.len = strlen.uint32
result.hash = hash.uint32 result.hash = hash.uint32
result.kind = noString
result.newObject()
if strlen > 0: if strlen > 0:
copyMem(result.chars[0].unsafeAddr, str[0].unsafeAddr, strlen) copyMem(result.chars[0].unsafeAddr, str[0].unsafeAddr, strlen)
@ -80,16 +69,15 @@ proc newString*(str: char): NdString =
if interned != nil: if interned != nil:
return interned return interned
let len = sizeof(NdStringObj) + 1 let len = 8 + 1
result = cast[NdString](ndAlloc(len)) result = cast[NdString](alloc(len))
result.len = 1.uint32 result.len = 1.uint32
result.hash = hash.uint32 result.hash = hash.uint32
result.chars[0] = str result.chars[0] = str
result.kind = noString
result.newObject()
discard ndStrings.tableSet(result, nil) discard ndStrings.tableSet(result, nil)
proc resetInternedStrings* = proc resetInternedStrings* =
ndStrings.free() ndStrings.free()
ndStrings = newTable[NdString, NdString]() ndStrings = newTable[NdString, NdString]()

View File

@ -1,8 +1,5 @@
import ../pointerutils import ../pointerutils
import ndobject
import ../memory
# configure stacks here # configure stacks here
import ../config import ../config
#const boundsChecks = defined(debug) #const boundsChecks = defined(debug)
@ -18,7 +15,7 @@ type
cap*: int cap*: int
proc newStack*[T](startingCap: int): Stack[T] = proc newStack*[T](startingCap: int): Stack[T] =
result.start = cast[ptr T](ndAlloc(startingCap * sizeof(T))) result.start = cast[ptr T](alloc(startingCap * sizeof(T)))
result.top = result.start.psub(sizeof(T)) result.top = result.start.psub(sizeof(T))
result.cap = startingCap result.cap = startingCap
@ -26,16 +23,14 @@ proc free*[T](stack: var Stack[T]) =
## dealloc's the stack object ## dealloc's the stack object
## if the stack contains pointers, those should be freed before destroying the stack ## if the stack contains pointers, those should be freed before destroying the stack
stack.cap = 0 stack.cap = 0
stack.start.ndDealloc() stack.start.dealloc()
stack.start = nil stack.start = nil
stack.top = nil stack.top = nil
proc grow[T](stack: var Stack[T], len: int) = proc grow[T](stack: var Stack[T], len: int) =
## growth the stack's capacity and increments the top's index by one ## growth the stack's capacity and increments the top's index by one
let oldcap = stack.cap stack.cap *= growthFactor
let newcap = stack.cap * growthFactor stack.start = cast[ptr T](realloc(stack.start, stack.cap * sizeof(T)))
stack.cap = newcap
stack.start = cast[ptr T](ndRealloc(stack.start, oldcap * sizeof(T), newcap * sizeof(T)))
stack.top = stack.start.padd(len * sizeof(T)) stack.top = stack.start.padd(len * sizeof(T))
proc shrink[T](stack: var Stack[T]) = proc shrink[T](stack: var Stack[T]) =

View File

@ -1,12 +1,7 @@
import strformat import strformat
import strutils import strutils
import bitops import bitops
export bitops
import ../config
import ndobject
export ndobject
import ndstring import ndstring
import ndlist import ndlist
import hashtable import hashtable
@ -26,12 +21,12 @@ type
# bits 49-48 determine type: # bits 49-48 determine type:
# if bit 63 is 0: # if bit 63 is 0:
# 00 -> nil or bool (singletons) # 00 -> nil or bool (singletons)
# 01 -> object (string, closure, list, table, upvalue) (formerly string) # 01 -> string
# 10 -> funct # 10 -> funct
# 11 -> (formerly closure) free # 11 -> closure
# if bit 63 is 1: # if bit 63 is 1:
# 00 -> (formerly list) free # 00 -> list
# 01 -> (formerly table) free # 01 -> table
# 10 -> native funct # 10 -> native funct
# 11 -> unused for now # 11 -> unused for now
@ -42,14 +37,13 @@ const ndTrue* = 0x7ffc000000000002'u
const ndFalse* = 0x7ffc000000000003'u const ndFalse* = 0x7ffc000000000003'u
# 0111 1111 1111 11*01* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 # 0111 1111 1111 11*01* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
#const tagString* = 0x7ffd000000000000'u const tagString* = 0x7ffd000000000000'u
const tagObject* = 0x7ffd000000000000'u
# 0111 1111 1111 11*10* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 # 0111 1111 1111 11*10* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
const tagFunct* = 0x7ffe000000000000'u const tagFunct* = 0x7ffe000000000000'u
# you can imagine these now... # you can imagine these now...
#const tagClosure* = 0x7fff000000000000'u const tagClosure* = 0x7fff000000000000'u
#const tagList* = 0xfffc000000000000'u const tagList* = 0xfffc000000000000'u
#const tagTable* = 0xfffd000000000000'u const tagTable* = 0xfffd000000000000'u
const tagNative* = 0xfffe000000000000'u const tagNative* = 0xfffe000000000000'u
const mask48* = 0xffff000000000000'u const mask48* = 0xffff000000000000'u
@ -65,26 +59,20 @@ template isBool*(val: NdValue): bool =
template isFloat*(val: NdValue): bool = template isFloat*(val: NdValue): bool =
val.bitand(qNan) != qNan val.bitand(qNan) != qNan
template asObject*(val: NdValue): ptr NdObject =
cast[ptr NdObject](val.bitand(mask48.bitnot))
template isObject*(val: NdValue): bool =
val.bitand(mask48) == tagObject
template isString*(val: NdValue): bool = template isString*(val: NdValue): bool =
val.isObject() and val.asObject().kind == noString val.bitand(mask48) == tagString
template isFunct*(val: NdValue): bool = template isFunct*(val: NdValue): bool =
val.bitand(mask48) == tagFunct val.bitand(mask48) == tagFunct
template isClosure*(val: NdValue): bool = template isClosure*(val: NdValue): bool =
val.isObject() and val.asObject().kind == noClosure val.bitand(mask48) == tagClosure
template isList*(val: NdValue): bool = template isList*(val: NdValue): bool =
val.isObject() and val.asObject().kind == noList val.bitand(mask48) == tagList
template isTable*(val: NdValue): bool = template isTable*(val: NdValue): bool =
val.isObject() and val.asObject().kind == noTable val.bitand(mask48) == tagTable
template isNative*(val: NdValue): bool = template isNative*(val: NdValue): bool =
val.bitand(mask48) == tagNative val.bitand(mask48) == tagNative
@ -124,7 +112,7 @@ template fromFloat*(val: float): NdValue =
cast[NdValue](val) cast[NdValue](val)
template fromNdString*(val: NdString): NdValue = template fromNdString*(val: NdString): NdValue =
cast[uint](val).bitor(tagObject) cast[uint](val).bitor(tagString)
template fromNimString*(sval: string): NdValue = template fromNimString*(sval: string): NdValue =
fromNdString(newString(sval)) fromNdString(newString(sval))
@ -133,13 +121,13 @@ template fromFunct*(val: ptr uint8): NdValue =
cast[uint](val).bitor(tagFunct) cast[uint](val).bitor(tagFunct)
template fromClosure*(val: Closure[NdValue]): NdValue = template fromClosure*(val: Closure[NdValue]): NdValue =
cast[uint](val).bitor(tagObject) cast[uint](val).bitor(tagClosure)
template fromList*(val: List[NdValue]): NdValue = template fromList*(val: List[NdValue]): NdValue =
cast[uint](val).bitor(tagObject) cast[uint](val).bitor(tagList)
template fromTable*(val: NdTable[NdValue, NdValue]): NdValue = template fromTable*(val: NdTable[NdValue, NdValue]): NdValue =
cast[uint](val).bitor(tagObject) cast[uint](val).bitor(tagTable)
template fromNative*(val: Native): NdValue = template fromNative*(val: Native): NdValue =
cast[uint](val).bitor(tagNative) cast[uint](val).bitor(tagNative)

View File

@ -4,8 +4,7 @@ import chunk
import config import config
import pointerutils import pointerutils
import types/ndstack import types/stack
import types/ndobject
import types/ndstring import types/ndstring
import bitops # needed for value's templates import bitops # needed for value's templates
import types/value import types/value
@ -16,9 +15,6 @@ import types/native
import lib/main import lib/main
import memory
import gc
when debugVM: when debugVM:
import terminal import terminal
@ -36,17 +32,20 @@ type
Frame = object Frame = object
stackBottom: int # the absolute index of where 0 inside the frame is stackBottom: int # the absolute index of where 0 inside the frame is
returnIp: ptr uint8 returnIp: ptr uint8
# closure: Closure[NdValue]
InterpretResult* = enum InterpretResult* = enum
irOK, irRuntimeError irOK, irRuntimeError
proc run*(chunk: Chunk): InterpretResult = proc run*(chunk: Chunk): InterpretResult =
enableGC = false
var var
ip: ptr uint8 = chunk.code[0].unsafeAddr ip: ptr uint8 = chunk.code[0].unsafeAddr
stack: Stack[NdValue] = newStack[NdValue](256)
hadError: bool hadError: bool
globals: Table[NdValue, NdValue]
frames: Stack[Frame] = newStack[Frame](4) frames: Stack[Frame] = newStack[Frame](4)
objects: ptr NdObject openUpvalues: Upvalue[NdValue] = nil
proc runtimeError(msg: string) = proc runtimeError(msg: string) =
let ii = ip.pdiff(chunk.code[0].unsafeAddr) let ii = ip.pdiff(chunk.code[0].unsafeAddr)
@ -142,7 +141,6 @@ proc run*(chunk: Chunk): InterpretResult =
let globalsVal = cast[NdTable[NdValue, NdValue]](globals.addr) let globalsVal = cast[NdTable[NdValue, NdValue]](globals.addr)
discard globals.tableSet(globalsKey, globalsVal.fromTable()) discard globals.tableSet(globalsKey, globalsVal.fromTable())
enableGC = true
while true: while true:
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma {.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
@ -161,6 +159,15 @@ proc run*(chunk: Chunk): InterpretResult =
msg &= "]" msg &= "]"
echo msg echo msg
when debugClosures:
msg = " Closures: [ "
#for i in 0 .. frames.high():
#if frames[i].closure != nil:
# msg &= debugStr(frames[i].closure) & " "
msg &= "]"
echo msg
var ii = ip.pdiff(chunk.code[0].unsafeAddr) - 1 var ii = ip.pdiff(chunk.code[0].unsafeAddr) - 1
var ll = -1 var ll = -1
setForegroundColor(fgYellow) setForegroundColor(fgYellow)
@ -354,7 +361,7 @@ proc run*(chunk: Chunk): InterpretResult =
of opSetUpvalue: of opSetUpvalue:
let slot = ip.readDU8() let slot = ip.readDU8()
when debugClosures: when debugClosures:
echo &"CLOSURES - setupvalue is setting {$stack.peek} to slot {slot}, number of slots: {cclosure.upvalueCount}" echo &"CLOSURES - setupvalue is setting {$stack.peek} to slot {slot}, number of slots: {frames.peek().closure.upvalueCount}"
cclosure.get(slot).write(stack.peek()) cclosure.get(slot).write(stack.peek())
of opCloseUpvalue: of opCloseUpvalue:
let slot = ip.readDU8() let slot = ip.readDU8()
@ -391,7 +398,9 @@ proc run*(chunk: Chunk): InterpretResult =
let times = runcounts[op] let times = runcounts[op]
echo &"OpCode: {op} total duration {dur} ms {times} times" echo &"OpCode: {op} total duration {dur} ms {times} times"
enableGC = false stack.free()
frames.free()
globals.free()
if hadError: if hadError:
irRuntimeError irRuntimeError