moved to using pointers for navigating the bytecode

This commit is contained in:
prod2 2022-01-22 04:46:53 +01:00
parent b170338dac
commit ab64d31271
4 changed files with 38 additions and 27 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@ main
compiler
*.txt
callgrind*
test.nim
test

View File

@ -53,6 +53,9 @@ proc toDU8*(integ: int): DoubleUint8 =
proc toInt*(du8: DoubleUint8): int =
cast[uint16](du8).int
proc DU8ptrToInt*(du8: ptr uint8): int =
cast[ptr uint16](du8)[].int
proc addConstant*(ch: var Chunk, constant: KonValue): int =
ch.constants.add(constant)
ch.constants.high

9
pointerutils.nim Normal file
View File

@ -0,0 +1,9 @@
template padd*[T](x: ptr T, num: int): ptr T =
cast[ptr T](cast[int](x) + num)
template psub*[T](x: ptr T, num: int): ptr T =
cast[ptr T](cast[int](x) - num)
template pdiff*[T](x: ptr T, y: ptr): int =
cast[int](x) - cast[int](y)

51
vm.nim
View File

@ -4,17 +4,17 @@ import tables
import value
import chunk
import config
import pointerutils
type
Frame = object
stackBottom: int # the absolute index of where 0 inside the frame is
ii: int
returnIp: ptr uint8
VM* = ref object
chunk: Chunk
ii: int
ip: ptr uint8
stack: seq[KonValue]
line: int
hadError: bool
globals: Table[string, KonValue]
frames: seq[Frame]
@ -24,7 +24,8 @@ type
proc newVM*(ch: Chunk): VM =
VM(chunk: ch, ii: 0, stack: @[], frames: @[Frame()])
result = VM(chunk: ch, stack: newSeqOfCap[KonValue](256), frames: newSeqOfCap[Frame](4))
result.ip = ch.code[0].unsafeAddr
proc push(vm: VM, val: KonValue) =
vm.stack.add(val)
@ -36,7 +37,9 @@ proc peek(vm: VM): KonValue =
vm.stack[vm.stack.high]
proc runtimeError(vm: VM, msg: string) =
write stderr, &"[line: {vm.line}] {msg}\n"
let ii = vm.ip.pdiff(vm.chunk.code[0].unsafeAddr)
let line = vm.chunk.lines[ii]
write stderr, &"[line: {line}] {msg}\n"
vm.hadError = true
proc pushSafe(vm: VM, val: KonValue): bool =
@ -51,12 +54,12 @@ proc pushSafe(vm: VM, val: KonValue): bool =
return true
proc advance(vm: VM): uint8 =
vm.ii.inc
vm.line = vm.chunk.lines[vm.ii-1]
vm.chunk.code[vm.ii-1]
result = vm.ip[]
vm.ip = vm.ip.padd(1)
proc readDU8(vm: VM): int =
[vm.advance, vm.advance].toInt
result = vm.ip.DU8ptrToInt
vm.ip = vm.ip.padd(argSize)
proc readConstant(vm: VM): KonValue =
let index = vm.readDU8()
@ -78,8 +81,9 @@ proc binary(op: OpCode, left: KonValue, right: KonValue): KonValue =
proc run*(vm: VM): InterpretResult =
template frameBottom: int = vm.frames[vm.frames.high].stackBottom
while true:
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
let ins = vm.advance.OpCode
when debugVM:
@ -94,8 +98,9 @@ proc run*(vm: VM): InterpretResult =
msg &= &"{e} "
msg &= "]"
echo msg
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
case ins:
of opPop:
discard vm.pop()
of opConstant:
let val: KonValue = vm.readConstant()
vm.push(val)
@ -109,11 +114,10 @@ proc run*(vm: VM): InterpretResult =
if not vm.pushSafe(binary(ins, left, right)):
break
of opReturn:
if frameBottom == 0:
if vm.frames.len == 0:
break
else:
discard vm.frames.pop() # remove frame that's over
vm.ii = vm.frames[vm.frames.high].ii # get backed up ii
vm.ip = vm.frames.pop().returnIp # remove frame that's over
of opTrue:
vm.push(toKonValue(true))
of opFalse:
@ -153,8 +157,6 @@ proc run*(vm: VM): InterpretResult =
else:
vm.runtimeError(&"Attempt to set undefined global variable {name}.")
break
of opPop:
discard vm.pop()
of opGetLocal:
let slot = vm.readDU8()
vm.push(vm.stack[slot + frameBottom])
@ -164,17 +166,17 @@ proc run*(vm: VM): InterpretResult =
of opJumpIfFalse:
let offset = vm.readDU8()
if vm.peek.isFalsey:
vm.ii += offset
vm.ip = vm.ip.padd(offset)
of opJumpIfFalsePop:
let offset = vm.readDU8()
if vm.pop.isFalsey:
vm.ii += offset
vm.ip = vm.ip.padd(offset)
of opJump:
let offset = vm.readDU8()
vm.ii += offset
vm.ip = vm.ip.padd(offset)
of opLoop:
let offset = vm.readDU8()
vm.ii -= offset
vm.ip = vm.ip.psub(offset)
of opCall:
# create the call env
# current stack before opCall:
@ -193,15 +195,10 @@ proc run*(vm: VM): InterpretResult =
vm.stack[vm.stack.high - argcount] = toKonValue() # replace the function with nil: this is the return value slot
# save ii
vm.frames[vm.frames.high].ii = vm.ii
# create new frame
vm.frames.add(Frame(stackBottom: vm.stack.high - argcount))
vm.ii = funct.entryII # jump to the entry point
vm.frames.add(Frame(stackBottom: vm.stack.high - argcount, returnIp: vm.ip))
vm.ip = vm.chunk.code[0].unsafeAddr.padd(funct.entryII) # jump to the entry point
when assertionsVM:
if not vm.hadError and vm.stack.len > 0: