2022-01-20 21:54:11 +01:00
|
|
|
import strformat
|
2022-01-29 05:12:33 +01:00
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
import chunk
|
|
|
|
import config
|
2022-01-22 04:46:53 +01:00
|
|
|
import pointerutils
|
2022-01-27 01:36:43 +01:00
|
|
|
|
2022-01-27 18:54:02 +01:00
|
|
|
import types/stack
|
2022-01-28 04:17:11 +01:00
|
|
|
import types/ndstring
|
2022-01-29 05:38:16 +01:00
|
|
|
import bitops # needed for value's templates
|
|
|
|
import types/value
|
|
|
|
import types/hashtable
|
2022-02-03 03:18:11 +01:00
|
|
|
import types/ndlist
|
2022-02-05 12:30:07 +01:00
|
|
|
import types/closure
|
2022-02-07 05:35:07 +01:00
|
|
|
import types/native
|
|
|
|
|
|
|
|
import lib/main
|
2022-01-27 18:54:02 +01:00
|
|
|
|
2022-02-06 07:35:00 +01:00
|
|
|
when debugVM:
|
|
|
|
import terminal
|
2022-01-29 05:12:33 +01:00
|
|
|
|
2022-01-22 17:28:53 +01:00
|
|
|
when profileInstructions:
|
|
|
|
import times
|
|
|
|
import std/monotimes
|
2022-01-20 21:54:11 +01:00
|
|
|
|
2022-01-28 04:17:11 +01:00
|
|
|
# not a perfect profiling approach, doing random stacktrace dumps
|
|
|
|
# x amount of times per second to get the current source line
|
|
|
|
# would be better
|
|
|
|
var durations: array[OpCode, Duration]
|
|
|
|
var runcounts: array[OpCode, float64]
|
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
type
|
2022-01-21 01:51:55 +01:00
|
|
|
Frame = object
|
|
|
|
stackBottom: int # the absolute index of where 0 inside the frame is
|
2022-01-22 04:46:53 +01:00
|
|
|
returnIp: ptr uint8
|
2022-02-06 10:04:49 +01:00
|
|
|
closure: Closure[NdValue]
|
2022-01-21 01:51:55 +01:00
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
InterpretResult* = enum
|
|
|
|
irOK, irRuntimeError
|
|
|
|
|
2022-01-27 01:36:43 +01:00
|
|
|
proc run*(chunk: Chunk): InterpretResult =
|
2022-01-20 21:54:11 +01:00
|
|
|
|
2022-01-27 01:36:43 +01:00
|
|
|
var
|
|
|
|
ip: ptr uint8 = chunk.code[0].unsafeAddr
|
2022-01-27 18:54:02 +01:00
|
|
|
stack: Stack[NdValue] = newStack[NdValue](256)
|
2022-01-27 01:36:43 +01:00
|
|
|
hadError: bool
|
2022-01-29 05:38:16 +01:00
|
|
|
globals: Table[NdValue, NdValue]
|
2022-01-28 04:17:11 +01:00
|
|
|
frames: Stack[Frame] = newStack[Frame](4)
|
2022-02-06 07:35:00 +01:00
|
|
|
openUpvalues: Upvalue[NdValue] = nil
|
2022-01-27 01:36:43 +01:00
|
|
|
|
|
|
|
proc runtimeError(msg: string) =
|
|
|
|
let ii = ip.pdiff(chunk.code[0].unsafeAddr)
|
|
|
|
let line = chunk.lines[ii]
|
|
|
|
write stderr, &"[line: {line}] {msg}\n"
|
|
|
|
hadError = true
|
|
|
|
|
2022-01-28 04:17:11 +01:00
|
|
|
frames.add(Frame(stackBottom: 0))
|
|
|
|
|
2022-01-27 18:54:02 +01:00
|
|
|
template popn(stack: var Stack[NdValue], amt: int) =
|
|
|
|
stack.deleteTopN(amt)
|
2022-01-27 03:32:42 +01:00
|
|
|
|
2022-02-06 02:46:26 +01:00
|
|
|
template readUI8(ip: var ptr uint8): int =
|
|
|
|
let res = ip[].int
|
2022-01-27 03:32:42 +01:00
|
|
|
ip = ip.padd(1)
|
2022-02-06 02:46:26 +01:00
|
|
|
res
|
2022-01-27 04:41:32 +01:00
|
|
|
|
2022-02-06 02:46:26 +01:00
|
|
|
template readDU8(ip: var ptr uint8): int =
|
|
|
|
let res = ip.DU8ptrToInt
|
2022-01-27 01:36:43 +01:00
|
|
|
ip = ip.padd(argSize)
|
2022-02-06 02:46:26 +01:00
|
|
|
res
|
2022-01-27 01:36:43 +01:00
|
|
|
|
2022-02-06 02:46:26 +01:00
|
|
|
template readConstant(ip: var ptr uint8, chunk: Chunk): NdValue =
|
|
|
|
chunk.constants[ip.readDU8()]
|
2022-01-27 03:32:42 +01:00
|
|
|
|
2022-01-29 06:12:08 +01:00
|
|
|
template frameBottom: int = frames.peek().stackBottom
|
2022-01-27 06:09:04 +01:00
|
|
|
|
2022-02-05 12:30:07 +01:00
|
|
|
template call(funct: NdValue, argcount: int, error: untyped) =
|
|
|
|
if funct.isFunct():
|
|
|
|
# create new frame
|
|
|
|
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip))
|
|
|
|
ip = funct.asFunct() # jump to the entry point
|
|
|
|
elif funct.isClosure():
|
2022-02-06 10:04:49 +01:00
|
|
|
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip, closure: funct.asClosure()))
|
2022-02-05 12:30:07 +01:00
|
|
|
ip = funct.asClosure().getIp()
|
2022-02-07 05:35:07 +01:00
|
|
|
elif funct.isNative():
|
|
|
|
var args: seq[NdValue] = newSeq[NdValue](argcount)
|
|
|
|
if argcount > 0:
|
|
|
|
copyMem(args[0].unsafeAddr, stack.getIndexNeg(argcount - 1).addr, argcount * sizeof(NdValue))
|
|
|
|
stack.deleteTopN(argcount)
|
|
|
|
let res = callNative(funct.asNative(), args, stack.peek())
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
error
|
2022-02-05 12:30:07 +01:00
|
|
|
else:
|
2022-02-07 05:35:07 +01:00
|
|
|
runtimeError("Attempt to call a non-funct (a defunct?).") # here is a bad defunct joke
|
2022-02-05 12:30:07 +01:00
|
|
|
error
|
|
|
|
|
2022-02-06 07:35:00 +01:00
|
|
|
proc captureUpvalue(location: ptr NdValue): Upvalue[NdValue] =
|
2022-02-06 10:04:49 +01:00
|
|
|
when debugClosures:
|
|
|
|
write stdout, "CLOSURES - captureUpvalue: "
|
2022-02-06 07:35:00 +01:00
|
|
|
var prev: Upvalue[NdValue]
|
|
|
|
var upvalue = openUpvalues
|
|
|
|
while upvalue != nil and upvalue.location.pgreater(location):
|
|
|
|
prev = upvalue
|
|
|
|
upvalue = upvalue.next
|
|
|
|
|
|
|
|
# existing upvalue
|
|
|
|
if upvalue != nil and upvalue.location == location:
|
2022-02-06 10:04:49 +01:00
|
|
|
when debugClosures:
|
|
|
|
write stdout, "found existing, returning that.\n"
|
2022-02-06 07:35:00 +01:00
|
|
|
return upvalue
|
|
|
|
|
|
|
|
# new upvalue
|
2022-02-06 10:04:49 +01:00
|
|
|
when debugClosures:
|
|
|
|
write stdout, "creating new.\n"
|
2022-02-06 07:35:00 +01:00
|
|
|
result = newUpvalue(location)
|
|
|
|
result.next = upvalue
|
|
|
|
|
|
|
|
if prev == nil:
|
|
|
|
openUpvalues = result
|
|
|
|
else:
|
|
|
|
prev.next = result
|
|
|
|
|
|
|
|
proc closeUpvalues(last: ptr NdValue) =
|
|
|
|
while openUpvalues != nil and openUpvalues.location.pge(last):
|
|
|
|
let upval = openUpvalues
|
|
|
|
upval.closed = upval.location[]
|
|
|
|
when debugClosures:
|
|
|
|
echo &"CLOSURES - closeUpvalues: closing on {upval.closed}"
|
|
|
|
upval.location = upval.closed.addr
|
|
|
|
openUpvalues = upval.next
|
|
|
|
|
2022-02-07 05:35:07 +01:00
|
|
|
# initialize globals
|
|
|
|
constructStdlib()
|
|
|
|
for i in 0 .. natives.high():
|
|
|
|
let native = i.uint32.fromNative()
|
|
|
|
let name = nativeNames[i].fromNimString()
|
|
|
|
discard globals.tableSet(name, native)
|
2022-02-07 06:03:47 +01:00
|
|
|
let globalsKey = "_G".fromNimString()
|
|
|
|
let globalsVal = cast[NdTable[NdValue, NdValue]](globals.addr)
|
|
|
|
discard globals.tableSet(globalsKey, globalsVal.fromTable())
|
2022-02-07 05:35:07 +01:00
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
while true:
|
2022-01-22 04:46:53 +01:00
|
|
|
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
|
|
|
|
2022-01-27 01:36:43 +01:00
|
|
|
let ins = ip[].OpCode
|
|
|
|
ip = ip.padd(1)
|
2022-01-21 01:51:55 +01:00
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
when debugVM:
|
2022-02-06 04:59:39 +01:00
|
|
|
var msg = ""
|
2022-01-20 21:54:11 +01:00
|
|
|
msg &= " Stack: [ "
|
2022-01-27 18:54:02 +01:00
|
|
|
for i in 0 .. stack.high():
|
2022-01-27 01:36:43 +01:00
|
|
|
let e = stack[i]
|
2022-01-21 01:51:55 +01:00
|
|
|
if i == frameBottom:
|
|
|
|
msg &= &"<{e}> "
|
|
|
|
else:
|
|
|
|
msg &= &"{e} "
|
2022-01-20 21:54:11 +01:00
|
|
|
msg &= "]"
|
|
|
|
echo msg
|
2022-02-06 07:35:00 +01:00
|
|
|
|
|
|
|
when debugClosures:
|
2022-02-06 10:04:49 +01:00
|
|
|
msg = " Closures: [ "
|
|
|
|
for i in 0 .. frames.high():
|
|
|
|
if frames[i].closure != nil:
|
|
|
|
msg &= debugStr(frames[i].closure) & " "
|
|
|
|
msg &= "]"
|
|
|
|
echo msg
|
2022-02-06 07:35:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
var ii = ip.pdiff(chunk.code[0].unsafeAddr) - 1
|
|
|
|
var ll = -1
|
|
|
|
setForegroundColor(fgYellow)
|
|
|
|
disassembleInstruction(chunk, ii, ll)
|
|
|
|
setForegroundColor(fgDefault)
|
|
|
|
write stdout, " "
|
2022-01-22 17:28:53 +01:00
|
|
|
|
|
|
|
when profileInstructions:
|
|
|
|
let startTime = getMonoTime()
|
2022-01-29 06:17:51 +01:00
|
|
|
runcounts[ins] += 1f
|
2022-01-22 17:28:53 +01:00
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
case ins:
|
2022-01-22 04:46:53 +01:00
|
|
|
of opPop:
|
2022-01-27 01:36:43 +01:00
|
|
|
discard stack.pop()
|
2022-01-27 03:32:42 +01:00
|
|
|
of opPopA:
|
2022-02-06 02:46:26 +01:00
|
|
|
let amt = ip.readDU8()
|
2022-01-27 03:32:42 +01:00
|
|
|
stack.popn(amt)
|
|
|
|
of opPopSA:
|
2022-02-06 02:46:26 +01:00
|
|
|
let amt = ip.readUI8()
|
2022-01-27 03:32:42 +01:00
|
|
|
stack.popn(amt)
|
2022-02-08 08:13:38 +01:00
|
|
|
of opSwap:
|
|
|
|
stack.swap()
|
2022-01-20 21:54:11 +01:00
|
|
|
of opConstant:
|
2022-02-06 02:46:26 +01:00
|
|
|
let val: NdValue = ip.readConstant(chunk)
|
2022-01-27 01:36:43 +01:00
|
|
|
stack.add(val)
|
2022-01-20 21:54:11 +01:00
|
|
|
of opNegate:
|
2022-01-27 06:09:04 +01:00
|
|
|
let res = stack.peek().negate()
|
2022-01-27 02:03:23 +01:00
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
break
|
|
|
|
of opAdd:
|
|
|
|
let right = stack.pop()
|
|
|
|
let res = stack.peek().add(right)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
2022-01-27 02:03:23 +01:00
|
|
|
of opSubtract:
|
|
|
|
let right = stack.pop()
|
|
|
|
let res = stack.peek().subtract(right)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
break
|
|
|
|
of opMultiply:
|
|
|
|
let right = stack.pop()
|
|
|
|
let res = stack.peek().multiply(right)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
break
|
|
|
|
of opDivide:
|
2022-01-27 01:36:43 +01:00
|
|
|
let right = stack.pop()
|
2022-01-27 02:03:23 +01:00
|
|
|
let res = stack.peek().divide(right)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
|
|
|
of opReturn:
|
2022-01-28 04:17:11 +01:00
|
|
|
if frames.len() == 1:
|
2022-01-21 01:51:55 +01:00
|
|
|
break
|
|
|
|
else:
|
2022-01-27 01:36:43 +01:00
|
|
|
ip = frames.pop().returnIp # remove frame that's over
|
2022-01-20 21:54:11 +01:00
|
|
|
of opTrue:
|
2022-01-29 05:12:33 +01:00
|
|
|
stack.add(fromBool(true))
|
2022-01-20 21:54:11 +01:00
|
|
|
of opFalse:
|
2022-01-29 05:12:33 +01:00
|
|
|
stack.add(fromBool(false))
|
2022-01-20 21:54:11 +01:00
|
|
|
of opNil:
|
2022-01-29 05:12:33 +01:00
|
|
|
stack.add(fromNil())
|
|
|
|
of opNot: # TODO hayago += optimization
|
|
|
|
stack.add(fromBool(stack.pop().isFalsey()))
|
2022-01-20 21:54:11 +01:00
|
|
|
of opEqual:
|
2022-01-29 05:12:33 +01:00
|
|
|
stack.add(fromBool(stack.pop().equal(stack.pop())))
|
2022-01-20 21:54:11 +01:00
|
|
|
of opLess:
|
2022-01-27 06:09:04 +01:00
|
|
|
let right = stack.pop()
|
|
|
|
let res = stack.peek().less(right)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
|
|
|
of opGreater:
|
2022-01-27 06:09:04 +01:00
|
|
|
let right = stack.pop()
|
|
|
|
let res = stack.peek().greater(right)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
|
|
|
of opDefineGlobal:
|
2022-02-06 02:46:26 +01:00
|
|
|
let name = ip.readConstant(chunk)
|
|
|
|
let existed = globals.tableSet(name, stack.pop())
|
2022-01-29 05:38:16 +01:00
|
|
|
if existed:
|
2022-01-27 01:36:43 +01:00
|
|
|
runtimeError("Attempt to redefine an existing global variable.")
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
|
|
|
of opGetGlobal:
|
2022-02-06 02:46:26 +01:00
|
|
|
let name = ip.readConstant(chunk)
|
2022-01-29 05:38:16 +01:00
|
|
|
var val: NdValue
|
2022-02-06 02:46:26 +01:00
|
|
|
let existed = globals.tableGet(name, val)
|
2022-01-29 05:38:16 +01:00
|
|
|
if existed:
|
|
|
|
stack.add(val)
|
2022-01-20 21:54:11 +01:00
|
|
|
else:
|
2022-01-27 01:36:43 +01:00
|
|
|
runtimeError(&"Undefined global variable {name}.")
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
|
|
|
of opSetGlobal:
|
2022-02-06 02:46:26 +01:00
|
|
|
let name = ip.readConstant(chunk)
|
|
|
|
let existed = globals.tableSet(name, stack.peek())
|
2022-01-29 05:38:16 +01:00
|
|
|
if not existed:
|
2022-02-06 07:35:00 +01:00
|
|
|
runtimeError("Attempt to assign to undefined global variable.")
|
2022-01-20 21:54:11 +01:00
|
|
|
break
|
|
|
|
of opGetLocal:
|
2022-02-06 02:46:26 +01:00
|
|
|
let slot = ip.readDU8()
|
2022-01-27 01:36:43 +01:00
|
|
|
stack.add(stack[slot + frameBottom])
|
2022-01-20 21:54:11 +01:00
|
|
|
of opSetLocal:
|
2022-02-06 02:46:26 +01:00
|
|
|
let slot = ip.readDU8()
|
2022-01-27 01:36:43 +01:00
|
|
|
stack[slot + frameBottom] = stack.peek()
|
2022-01-20 21:54:11 +01:00
|
|
|
of opJumpIfFalse:
|
2022-02-06 02:46:26 +01:00
|
|
|
let offset = ip.readDU8()
|
2022-01-29 07:24:58 +01:00
|
|
|
if stack.peek().isFalsey():
|
2022-01-27 01:36:43 +01:00
|
|
|
ip = ip.padd(offset)
|
2022-01-20 21:54:11 +01:00
|
|
|
of opJumpIfFalsePop:
|
2022-02-06 02:46:26 +01:00
|
|
|
let offset = ip.readDU8()
|
2022-01-29 07:24:58 +01:00
|
|
|
if stack.pop().isFalsey():
|
2022-01-27 01:36:43 +01:00
|
|
|
ip = ip.padd(offset)
|
2022-01-20 21:54:11 +01:00
|
|
|
of opJump:
|
2022-02-06 02:46:26 +01:00
|
|
|
let offset = ip.readDU8()
|
2022-01-27 01:36:43 +01:00
|
|
|
ip = ip.padd(offset)
|
2022-01-20 21:54:11 +01:00
|
|
|
of opLoop:
|
2022-02-06 02:46:26 +01:00
|
|
|
let offset = ip.readDU8()
|
2022-01-27 01:36:43 +01:00
|
|
|
ip = ip.psub(offset)
|
2022-01-29 20:43:13 +01:00
|
|
|
of opFunctionDef:
|
2022-02-06 02:46:26 +01:00
|
|
|
let offset = ip.readDU8()
|
2022-01-29 20:43:13 +01:00
|
|
|
let faddr: ptr uint8 = ip
|
|
|
|
ip = ip.padd(offset)
|
|
|
|
stack.push(faddr.fromFunct())
|
2022-02-06 04:59:39 +01:00
|
|
|
|
2022-01-27 05:56:09 +01:00
|
|
|
of opCheckArity:
|
2022-02-06 02:46:26 +01:00
|
|
|
let arity = ip.readUI8()
|
2022-01-27 05:56:09 +01:00
|
|
|
let argcount = stack.high() - frameBottom
|
|
|
|
if arity != argcount:
|
|
|
|
runtimeError(&"Wrong number of arguments, expected {arity}, got {argcount}.")
|
|
|
|
break
|
2022-01-21 01:51:55 +01:00
|
|
|
of opCall:
|
|
|
|
# create the call env
|
|
|
|
# current stack before opCall:
|
|
|
|
# ... <funct obj> <arg1> <arg2> <arg3>
|
|
|
|
# opCall converts it to this
|
|
|
|
# ... <ret val> <arg1> <arg2> <arg3>
|
2022-02-06 02:46:26 +01:00
|
|
|
let argcount = ip.readUI8()
|
2022-01-28 04:17:11 +01:00
|
|
|
let funct = stack.getIndexNeg(argcount)
|
2022-01-21 01:51:55 +01:00
|
|
|
|
2022-01-29 05:12:33 +01:00
|
|
|
stack.setIndexNeg(argcount, fromNil()) # replace the function with nil: this is the return value slot
|
2022-02-05 12:30:07 +01:00
|
|
|
funct.call(argcount):
|
|
|
|
break
|
2022-02-03 03:18:11 +01:00
|
|
|
of opCreateList:
|
2022-02-06 02:46:26 +01:00
|
|
|
let listLen = ip.readDU8()
|
2022-02-03 04:56:16 +01:00
|
|
|
if listLen == 0:
|
|
|
|
stack.push(newList[NdValue]().fromList())
|
|
|
|
else:
|
|
|
|
let start = stack.getIndexNeg(listLen - 1).addr
|
|
|
|
var list = newListCopymem[NdValue](start, listLen)
|
2022-02-05 03:24:30 +01:00
|
|
|
stack.deleteTopN(listLen)
|
2022-02-03 04:56:16 +01:00
|
|
|
stack.push(list.fromList())
|
2022-02-03 03:18:11 +01:00
|
|
|
of opCreateTable:
|
2022-02-06 02:46:26 +01:00
|
|
|
let tblLen = ip.readDU8()
|
2022-02-03 04:56:16 +01:00
|
|
|
var tbl = newNdTable[NdValue, NdValue](tblLen)
|
|
|
|
for i in countup(0, tblLen - 1):
|
2022-02-03 03:18:11 +01:00
|
|
|
let val = stack.pop()
|
|
|
|
let key = stack.pop()
|
2022-02-03 04:56:16 +01:00
|
|
|
if tbl[].tableSet(key, val):
|
|
|
|
runtimeError("Attempt to redefine an existing value inside table declaration.")
|
|
|
|
break
|
2022-02-05 12:37:54 +01:00
|
|
|
# stack.deleteTopN(tblLen * 2) # THIS IS NOT NEEDED, pops are done
|
2022-02-03 03:18:11 +01:00
|
|
|
stack.push(tbl.fromTable())
|
|
|
|
of opLen:
|
|
|
|
let res = stack.peek().getLength()
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
break
|
|
|
|
of opGetIndex:
|
|
|
|
let index = stack.pop()
|
2022-02-05 02:45:29 +01:00
|
|
|
let res = stack.peek().getIndex(index) # getIndex modifies the top value of the stack
|
2022-02-03 03:18:11 +01:00
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
break
|
|
|
|
of opSetIndex:
|
|
|
|
let value = stack.pop()
|
|
|
|
let index = stack.pop()
|
|
|
|
let res = stack.peek().setIndex(index, value)
|
|
|
|
if not res.ok:
|
|
|
|
runtimeError(res.msg)
|
|
|
|
break
|
2022-02-07 05:35:07 +01:00
|
|
|
of opGetUpvalue:
|
|
|
|
let slot = ip.readDU8()
|
|
|
|
let val = frames.peek().closure.get(slot).read()
|
|
|
|
when debugClosures:
|
|
|
|
echo &"CLOSURES - getupvalue got {val} from slot {slot}"
|
|
|
|
stack.push(val)
|
|
|
|
of opSetUpvalue:
|
|
|
|
let slot = ip.readDU8()
|
|
|
|
when debugClosures:
|
|
|
|
echo &"CLOSURES - setupvalue is setting {$stack.peek} to slot {slot}, number of slots: {frames.peek().closure.upvalueCount}"
|
|
|
|
frames.peek().closure.get(slot).write(stack.peek())
|
|
|
|
of opCloseUpvalue:
|
|
|
|
let slot = ip.readDU8()
|
|
|
|
stack[slot + frameBottom].addr.closeUpvalues()
|
|
|
|
of opClosure:
|
|
|
|
let upvalCount = ip.readDU8()
|
|
|
|
let funct = stack.peek()
|
|
|
|
let closure = newClosure[NdValue](funct.asFunct(), upvalCount)
|
|
|
|
stack.settip(closure.fromClosure())
|
|
|
|
for i in countup(0, upvalCount - 1):
|
|
|
|
let slot = ip.readDU8()
|
|
|
|
let isLocal = ip.readUI8() == 0
|
|
|
|
if isLocal:
|
|
|
|
let loc = stack[slot + frameBottom].addr
|
|
|
|
when debugClosures:
|
|
|
|
echo &"CLOSURES - opClosure: local upvalue {loc[]} from local slot {slot} to slot {i}"
|
|
|
|
closure.set(i, loc.captureUpvalue())
|
|
|
|
else:
|
|
|
|
let val = frames.peek().closure.get(slot)
|
|
|
|
when debugClosures:
|
|
|
|
echo &"CLOSURES - opClosure: non local upvalue {val.location[]} from slot {slot} to slot {i}"
|
|
|
|
closure.set(i, val)
|
2022-01-20 21:54:11 +01:00
|
|
|
|
2022-01-22 17:28:53 +01:00
|
|
|
when profileInstructions:
|
|
|
|
durations[ins] += getMonoTime() - startTime
|
|
|
|
|
2022-01-20 21:54:11 +01:00
|
|
|
when assertionsVM:
|
2022-01-27 01:36:43 +01:00
|
|
|
if not hadError and stack.len > 0:
|
|
|
|
runtimeError(&"VM Assertion failed: stack is of non-zero length {stack.len} after execution has finished.")
|
2022-01-22 17:28:53 +01:00
|
|
|
|
|
|
|
when profileInstructions:
|
|
|
|
for op in OpCode:
|
|
|
|
let dur = durations[op].inMilliseconds
|
2022-01-28 04:17:11 +01:00
|
|
|
let times = runcounts[op]
|
|
|
|
echo &"OpCode: {op} total duration {dur} ms {times} times"
|
|
|
|
|
2022-01-28 22:00:21 +01:00
|
|
|
stack.free()
|
|
|
|
frames.free()
|
2022-01-29 06:12:08 +01:00
|
|
|
globals.free()
|
2022-01-22 17:28:53 +01:00
|
|
|
|
2022-01-27 01:36:43 +01:00
|
|
|
if hadError:
|
2022-01-20 21:54:11 +01:00
|
|
|
irRuntimeError
|
|
|
|
else:
|
|
|
|
irOK
|
|
|
|
|
|
|
|
|