Various fixes to frames, recursion, and more. Removed stack bottom from CFI data. Added comparison opcode for fib test as well as a clock opcode

This commit is contained in:
Mattia Giambirtone 2022-08-01 10:36:06 +02:00
parent b4628109ce
commit ff0ae8fcba
6 changed files with 111 additions and 145 deletions

View File

@ -60,21 +60,19 @@ below:
The CFI segment (where CFI stands for **C**all **F**rame **I**nformation), contains details about each function in
the original file. The segment's size is fixed and is encoded at the beginning as a sequence of 4 bytes (i.e. a single 32 bit integer).
The data
in this segment can be decoded as explained in [this file](../src/frontend/meta/bytecode.nim#L41), which is quoted
The data in this segment can be decoded as explained in [this file](../src/frontend/meta/bytecode.nim#L41), which is quoted
below:
```
[...]
## cfi represents Call Frame Information and encodes the following information:
## - Function name
## - Stack bottom
## - Argument count
## - Function boundaries
## The encoding for CFI data is the following:
## - First, the position into the bytecode where the function begins is encoded (as a 3 byte integer)
## - Second, the position into the bytecode where the function ends is encoded (as a 3 byte integer)
## - Then, the frame's stack bottom is encoded as a 3 byte integer
## - After the frame's stack bottom follows the argument count as a 1 byte integer
## - After that follows the argument count as a 1 byte integer
## - Lastly, the function's name (optional) is encoded in ASCII, prepended with
## its size as a 2-byte integer
[...]

View File

@ -103,5 +103,10 @@ proc `$`*(self: PeonObject): string =
result = "typevar"
of String:
result = self.str
of Bool:
if self.boolean:
result = "true"
else:
result = "false"
else:
discard

View File

@ -13,8 +13,9 @@
# limitations under the License.
## The Peon runtime environment
import strutils
import strformat
import std/monotimes
import types
import ../config
@ -23,6 +24,10 @@ import ../util/multibyte
export types
when DEBUG_TRACE_VM:
import strutils
import strformat
type
PeonVM* = ref object
@ -396,14 +401,18 @@ proc dispatch*(self: PeonVM) =
# in a hidden function, so this
# will also exit the VM if we're
# at the end of the program
let ret = self.popc()
while self.calls.len() > self.frames[^1] + 2:
# Discards the function's local variables,
# if there is any
discard self.popc()
let ret = self.popc() # Return address
discard self.popc() # Function object
if self.readByte() == 1:
# Function is non-void!
self.push(self.results.pop())
else:
discard self.results.pop()
# Discard a stack frame
# Discard the topmost stack frame
discard self.frames.pop()
if self.frames.len() == 0:
# End of the program!
@ -489,106 +498,87 @@ proc dispatch*(self: PeonVM) =
else:
discard self.pop()
# Built-in operations on primitive types
# Note how
of AddInt64:
self.push(PeonObject(kind: Int64, long: self.pop().long + self.pop().long))
of SubInt64:
let second = self.pop()
self.push(PeonObject(kind: Int64, long: self.pop().long - second.long))
self.push(PeonObject(kind: Int64, long: self.pop().long - self.pop().long))
of MulInt64:
self.push(PeonObject(kind: Int64, long: self.pop().long * self.pop().long))
of DivInt64:
let second = self.pop()
self.push(PeonObject(kind: Int64, long: self.pop().long div second.long))
self.push(PeonObject(kind: Int64, long: self.pop().long div self.pop().long))
of AddUInt64:
self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong + self.pop().uLong))
of SubUInt64:
let second = self.pop()
self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong - second.uLong))
self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong - self.pop().uLong))
of MulUInt64:
self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong * self.pop().uLong))
of DivUInt64:
let second = self.pop()
self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong div second.uLong))
self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong div self.pop().uLong))
of AddInt32:
self.push(PeonObject(kind: Int32, `int`: self.pop().`int` + self.pop().`int`))
of SubInt32:
let second = self.pop()
self.push(PeonObject(kind: Int32, `int`: self.pop().`int` - second.`int`))
self.push(PeonObject(kind: Int32, `int`: self.pop().`int` - self.pop().`int`))
of MulInt32:
self.push(PeonObject(kind: Int32, `int`: self.pop().`int` * self.pop().`int`))
of DivInt32:
let second = self.pop()
self.push(PeonObject(kind: Int32, `int`: self.pop().`int` div second.`int`))
self.push(PeonObject(kind: Int32, `int`: self.pop().`int` div self.pop().`int`))
of AddUInt32:
self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt + self.pop().uInt))
of SubUInt32:
let second = self.pop()
self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt - second.uInt))
self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt - self.pop().uInt))
of MulUInt32:
self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt * self.pop().uInt))
of DivUInt32:
let second = self.pop()
self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt div second.uInt))
self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt div self.pop().uInt))
of AddInt16:
self.push(PeonObject(kind: Int16, short: self.pop().short + self.pop().short))
of SubInt16:
let second = self.pop()
self.push(PeonObject(kind: Int16, short: self.pop().short - second.short))
self.push(PeonObject(kind: Int16, short: self.pop().short - self.pop().short))
of MulInt16:
self.push(PeonObject(kind: Int16, short: self.pop().short * self.pop().short))
of DivInt16:
let second = self.pop()
self.push(PeonObject(kind: Int16, short: self.pop().short div second.short))
self.push(PeonObject(kind: Int16, short: self.pop().short div self.pop().short))
of AddUInt16:
self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort + self.pop().uShort))
of SubUInt16:
let second = self.pop()
self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort - second.uShort))
self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort - self.pop().uShort))
of MulUInt16:
self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort * self.pop().uShort))
of DivUInt16:
let second = self.pop()
self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort div second.uShort))
self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort div self.pop().uShort))
of AddInt8:
self.push(PeonObject(kind: Int8, tiny: self.pop().tiny + self.pop().tiny))
of SubInt8:
let second = self.pop()
self.push(PeonObject(kind: Int8, tiny: self.pop().tiny - second.tiny))
self.push(PeonObject(kind: Int8, tiny: self.pop().tiny - self.pop().tiny))
of MulInt8:
self.push(PeonObject(kind: Int8, tiny: self.pop().tiny * self.pop().tiny))
of DivInt8:
let second = self.pop()
self.push(PeonObject(kind: Int8, tiny: self.pop().tiny div second.tiny))
self.push(PeonObject(kind: Int8, tiny: self.pop().tiny div self.pop().tiny))
of AddUInt8:
self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny + self.pop().uTiny))
of SubUInt8:
let second = self.pop()
self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny - second.uTiny))
self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny - self.pop().uTiny))
of MulUInt8:
self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny * self.pop().uTiny))
of DivUInt8:
let second = self.pop()
self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny div second.uTiny))
self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny div self.pop().uTiny))
of AddFloat64:
self.push(PeonObject(kind: Float64, `float`: self.pop().`float` + self.pop().`float`))
of SubFloat64:
let second = self.pop()
self.push(PeonObject(kind: Float64, `float`: self.pop().`float` - second.`float`))
self.push(PeonObject(kind: Float64, `float`: self.pop().`float` - self.pop().`float`))
of MulFloat64:
self.push(PeonObject(kind: Float64, `float`: self.pop().`float` * self.pop().`float`))
of DivFloat64:
let second = self.pop()
self.push(PeonObject(kind: Float64, `float`: self.pop().`float` / second.`float`))
self.push(PeonObject(kind: Float64, `float`: self.pop().`float` / self.pop().`float`))
of AddFloat32:
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat + self.pop().halfFloat))
of SubFloat32:
let second = self.pop()
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat - second.halfFloat))
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat - self.pop().halfFloat))
of MulFloat32:
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat * self.pop().halfFloat))
of DivFloat32:
let second = self.pop()
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat / second.halfFloat))
self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat / self.pop().halfFloat))
of NegInt64:
self.push(PeonObject(kind: Int64, long: -self.pop().long))
of NegInt32:
@ -601,6 +591,10 @@ proc dispatch*(self: PeonVM) =
self.push(PeonObject(kind: Float64, `float`: -self.pop().`float`))
of NegFloat32:
self.push(PeonObject(kind: Float32, halfFloat: -self.pop().halfFloat))
of LessThanInt64:
self.push(PeonObject(kind: Bool, boolean: self.pop().long < self.pop().long))
of SysClock64:
self.push(PeonObject(kind: Float64, `float`: getMonoTime().ticks().float() / 1_000_000_000))
else:
discard

View File

@ -373,27 +373,23 @@ proc resolve(self: Compiler, name: IdentExpr,
return nil
proc getStackPos(self: Compiler, name: IdentExpr, depth: int = self.scopeDepth): int =
proc getStackPos(self: Compiler, name: Name, depth: int = self.scopeDepth): int =
## Returns the predicted call stack position of a given name, relative
## to the current frame
var found = false
result = self.names.len()
for variable in reversed(self.names):
result = 2
for variable in self.names:
if variable.isFunDecl:
continue
dec(result)
if name.name.lexeme == variable.name.name.lexeme:
if variable.isPrivate and variable.owner != self.currentModule:
continue
else:
found = true
inc(result)
break
if name == variable:
found = true
break
inc(result)
if not found:
return -1
proc getClosurePos(self: Compiler, name: IdentExpr): int =
proc getClosurePos(self: Compiler, name: Name): int =
## Iterates the internal list of declared closure names backwards and
## returns the predicted closure array position of a given name.
## Returns -1 if the name can't be found (this includes names that
@ -401,12 +397,9 @@ proc getClosurePos(self: Compiler, name: IdentExpr): int =
result = self.closedOver.high()
var found = false
for variable in reversed(self.closedOver):
if name.name.lexeme == variable.name.name.lexeme:
if variable.isPrivate and variable.owner != self.currentModule:
continue
else:
found = true
break
if name == variable:
found = true
break
dec(result)
if not found:
return -1
@ -446,18 +439,16 @@ proc detectClosureVariable(self: Compiler, name: var Name, depth: int = self.sco
# put in place for us into a StoreClosure. We also update
# the name's isClosedOver field so that self.identifier()
# can emit a LoadClosure instruction instead of a LoadVar
self.closedOver.add(name)
if self.closedOver.len() >= 16777216:
self.error("too many consecutive closed-over variables (max is 16777215)")
name.isClosedOver = true
if not name.isFunctionArgument:
# We handle closed-over function arguments later
self.closedOver.add(name)
if self.closedOver.len() >= 16777216:
self.error("too many consecutive closed-over variables (max is 16777215)")
name.isClosedOver = true
self.chunk.code[name.codePos] = StoreClosure.uint8()
for i, b in self.closedOver.high().toTriple():
self.chunk.code[name.codePos + i + 1] = b
else:
discard
# self.error("it is currently not possible to close over function arguments")
proc compareTypes(self: Compiler, a, b: Type): bool =
@ -613,14 +604,15 @@ proc inferType(self: Compiler, node: Expression): Type =
else:
result = node.name.lexeme.toIntrinsic()
of unaryExpr:
return self.inferType(UnaryExpr(node).a)
let f = self.inferType(newIdentExpr(UnaryExpr(node).operator))
if f.isNil():
return f
return f.returnType
of binaryExpr:
let node = BinaryExpr(node)
var a = self.inferType(node.a)
var b = self.inferType(node.b)
if not self.compareTypes(a, b):
return nil
return a
let f = self.inferType(newIdentExpr(BinaryExpr(node).operator))
if f.isNil():
return f
return f.returnType
of {intExpr, hexExpr, binExpr, octExpr,
strExpr, falseExpr, trueExpr, infExpr,
nanExpr, floatExpr, nilExpr
@ -655,6 +647,8 @@ proc inferType(self: Compiler, node: Expression): Type =
result = Type(kind: Reference, value: self.inferType(Ref(node).value))
of ptrExpr:
result = Type(kind: Pointer, value: self.inferType(Ptr(node).value))
of groupingExpr:
result = self.inferType(GroupingExpr(node).expression)
else:
discard # Unreachable
@ -787,7 +781,7 @@ proc check(self: Compiler, term: Expression, kind: Type) =
self.error(&"call to undeclared function '{CallExpr(term).callee.token.lexeme}'")
self.error(&"expecting value of type '{self.typeToStr(kind)}', but expression has no type")
elif not self.compareTypes(k, kind):
self.error(&"expecting value of type '{self.typeToStr(k)}', got '{self.typeToStr(k)}' instead")
self.error(&"expecting value of type '{self.typeToStr(kind)}', got '{self.typeToStr(k)}' instead")
@ -803,10 +797,10 @@ proc emitFunction(self: Compiler, name: Name) =
# load it
elif not name.isClosedOver:
self.emitByte(LoadVar)
self.emitBytes(self.getStackPos(name.name).toTriple())
self.emitBytes(self.getStackPos(name).toTriple())
else:
self.emitByte(LoadClosure)
self.emitBytes(self.getClosurePos(name.name).toTriple())
self.emitBytes(self.getClosurePos(name).toTriple())
## End of utility functions
@ -898,7 +892,9 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
if fn.valueType.builtinOp notin ["GenericLogicalOr", "GenericLogicalAnd"]:
if len(args) == 2:
self.expression(args[1])
self.expression(args[0])
self.expression(args[0])
elif len(args) == 1:
self.expression(args[0])
case fn.valueType.builtinOp:
of "AddInt64":
self.emitByte(AddInt64)
@ -965,13 +961,13 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
of "MulUInt8":
self.emitByte(MulUInt8)
of "AddFloat64":
self.emitByte(AddInt8)
self.emitByte(AddFloat64)
of "SubFloat64":
self.emitByte(SubInt8)
self.emitByte(SubFloat64)
of "DivFloat64":
self.emitByte(DivInt8)
self.emitByte(DivFloat64)
of "MulFloat64":
self.emitByte(MulInt8)
self.emitByte(MulFloat64)
of "AddFloat32":
self.emitByte(AddFloat32)
of "SubFloat32":
@ -1002,6 +998,10 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
var jump = self.emitJump(JumpIfFalseOrPop)
self.expression(args[1])
self.patchJump(jump)
of "LessThanInt64":
self.emitByte(LessThanInt64)
of "SysClock64":
self.emitByte(SysClock64)
else:
self.error(&"unknown built-in: '{fn.valueType.builtinOp}'")
@ -1186,13 +1186,13 @@ proc identifier(self: Compiler, node: IdentExpr) =
# Static name resolution, loads value at index in the stack. Very fast. Much wow.
self.emitByte(LoadVar)
# No need to check for -1 here: we already did a nil-check above!
self.emitBytes(self.getStackPos(s.name).toTriple())
self.emitBytes(self.getStackPos(s).toTriple())
else:
# Loads a closure variable. Stored in a separate "closure array" in the VM that does not
# align its semantics with the call stack. This makes closures work as expected and is
# not much slower than indexing our stack (since they're both dynamic arrays at runtime anyway)
self.emitByte(LoadClosure)
self.emitBytes(self.getClosurePos(s.name).toTriple())
self.emitBytes(self.getClosurePos(s).toTriple())
proc assignment(self: Compiler, node: ASTNode) =
@ -1212,13 +1212,13 @@ proc assignment(self: Compiler, node: ASTNode) =
self.detectClosureVariable(r)
if not r.isClosedOver:
self.emitByte(StoreVar)
self.emitBytes(self.getStackPos(name).toTriple())
self.emitBytes(self.getStackPos(r).toTriple())
else:
# Loads a closure variable. Stored in a separate "closure array" in the VM that does not
# align its semantics with the call stack. This makes closures work as expected and is
# not much slower than indexing our stack (since they're both dynamic arrays at runtime anyway)
self.emitByte(StoreClosure)
self.emitBytes(self.getClosurePos(name).toTriple())
self.emitBytes(self.getClosurePos(r).toTriple())
of setItemExpr:
let node = SetItemExpr(node)
let typ = self.inferType(node)
@ -1436,44 +1436,14 @@ proc deferStmt(self: Compiler, node: DeferStmt) =
self.chunk.code.delete(i) # TODO: Do not change bytecode size
proc endFunctionBeforeReturn(self: Compiler) =
## Emits code to clear a function's
## stack frame right before executing
## its return instruction
var popped = 0
for name in self.names:
if name.depth == self.scopeDepth and name.valueType.kind notin {Generic, CustomType} and not name.isFunDecl:
inc(popped)
if popped > 1:
self.emitByte(PopN)
self.emitBytes(popped.toDouble())
dec(popped, uint16.high().int)
while popped > 0:
self.emitByte(PopC)
dec(popped)
proc returnStmt(self: Compiler, node: ReturnStmt) =
## Compiles return statements
let actual = self.inferType(node.value)
var expected = self.currentFunction.returnType
if not expected.isNil() and expected.kind == Generic:
expected = actual
if actual.isNil() and not expected.isNil():
if not node.value.isNil():
if node.value.kind == identExpr:
self.error(&"reference to undeclared name '{node.value.token.lexeme}'")
elif node.value.kind == callExpr and CallExpr(node.value).callee.kind == identExpr:
self.error(&"call to undeclared function '{CallExpr(node.value).callee.token.lexeme}'")
self.error(&"expected return value of type '{self.typeToStr(expected)}', but expression has no type")
elif expected.isNil() and not actual.isNil():
self.error("void function cannot return any value")
elif not self.compareTypes(actual, expected):
self.error(&"expected return value of type '{self.typeToStr(expected)}', got '{self.typeToStr(actual)}' instead")
self.check(node.value, expected)
if not node.value.isNil():
self.expression(node.value)
self.emitByte(OpCode.SetResult)
self.endFunctionBeforeReturn()
self.emitByte(OpCode.Return)
if not node.value.isNil():
self.emitByte(1)
@ -1617,7 +1587,7 @@ proc varDecl(self: Compiler, node: VarDecl) =
self.expression(node.value)
self.declareName(node, mutable=node.token.kind == TokenType.Var)
self.emitByte(StoreVar)
self.emitBytes((self.getStackPos(self.names[^1].name) + 1).toTriple())
self.emitBytes((self.getStackPos(self.names[^1]) + 1).toTriple())
proc typeDecl(self: Compiler, node: TypeDecl) =
@ -1683,6 +1653,7 @@ proc fixGenericFunc(self: Compiler, name: Name, args: seq[Expression]): Type =
self.error(&"cannot specialize generic function: argument {i + 1} has no type")
proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression] = @[]) =
## Compiles function declarations
#[if not node.isNil():
@ -1697,18 +1668,16 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
var fn = if fn.isNil(): self.names[^(node.arguments.len() + 1)] else: fn
if fn.valueType.isBuiltinFunction:
# We take the arguments off of our name list
# because they become temporaries on the stack
for i in self.names.high() - node.arguments.high()..self.names.high():
self.names.delete(i)
else:
var function = self.currentFunction
var jmp: int
# because they become temporaries on the stack.
# Builtin functions (usually) map to a single
# bytecode instruction to avoid unnecessary
# overhead from peon's calling convention
# This also means that peon's fast builtins
# can only be relatively simple
self.frames.add(self.names.high())
self.names = self.names[0..^node.arguments.len() + 1]
else:
var function = self.currentFunction
var jmp: int
# A function's code is just compiled linearly
# and then jumped over
jmp = self.emitJump(JumpForwards)
@ -1776,7 +1745,6 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
# Some debugging info here
self.chunk.cfi.add(start.toTriple())
self.chunk.cfi.add(self.chunk.code.high().toTriple())
self.chunk.cfi.add(self.frames[^1].toTriple())
self.chunk.cfi.add(uint8(node.arguments.len()))
if not node.name.isNil():
self.chunk.cfi.add(fn.name.token.lexeme.len().toDouble())
@ -1786,7 +1754,7 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
self.chunk.cfi.add(s.toBytes())
else:
self.chunk.cfi.add(0.toDouble())
# Currently defer is not functional so we
# Currently defer is not functional, so we
# just pop the instructions
for _ in deferStart..self.deferred.high():
discard self.deferred.pop()
@ -1834,6 +1802,7 @@ proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk =
self.currentFunction = nil
self.currentModule = self.file.extractFilename()
self.current = 0
self.frames = @[0]
# Every peon program has a hidden entry point in
# which user code is wrapped. Think of it as if
# peon is implicitly writing the main() function
@ -1853,7 +1822,8 @@ proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk =
valueType: Type(kind: Function,
name: "",
returnType: nil,
args: @[]),
args: @[],
),
codePos: 13, # Jump address is hardcoded
name: newIdentExpr(Token(lexeme: "", kind: Identifier)),
isFunDecl: true,
@ -1871,5 +1841,5 @@ proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk =
self.endScope()
self.patchReturnAddress(pos)
self.emitByte(OpCode.Return)
self.emitByte(0) # Entry point has no return value
self.emitByte(0) # Entry point has no return value (TODO: Add easter eggs, cuz why not)
result = self.chunk

View File

@ -40,13 +40,12 @@ type
## the same line number multiple times and waste considerable amounts of space.
## cfi represents Call Frame Information and encodes the following information:
## - Function name
## - Stack bottom
## - Argument count
## - Function boundaries
## The encoding for CFI data is the following:
## - First, the position into the bytecode where the function begins is encoded (as a 3 byte integer)
## - Second, the position into the bytecode where the function ends is encoded (as a 3 byte integer)
## - Then, the frame's stack bottom is encoded as a 3 byte integer
## - After the frame's stack bottom follows the argument count as a 1 byte integer
## - After that follows the argument count as a 1 byte integer
## - Lastly, the function's name (optional) is encoded in ASCII, prepended with
## its size as a 2-byte integer
consts*: seq[uint8]
@ -137,6 +136,8 @@ type
SubFloat32,
DivFloat32,
MulFloat32,
LessThanInt64,
SysClock64,
## Basic stack operations
Pop, # Pops an element off the stack and discards it
PopRepl, # Same as Pop, but also prints the value of what's popped (used in REPL mode)
@ -198,7 +199,8 @@ const simpleInstructions* = {Return, LoadNil,
SubFloat64, DivFloat64, MulFloat64,
AddFloat32, SubFloat32, DivFloat32,
MulFloat32, NegFloat32, NegFloat64,
}
LessThanInt64, SysClock64
}
# Constant instructions are instructions that operate on the bytecode constant table
const constantInstructions* = {LoadInt64, LoadUInt64,

View File

@ -71,7 +71,6 @@ proc checkFrameStart(self: Debugger, n: int) =
styledEcho fgBlue, "\n==== Peon Bytecode Debugger - Begin Frame ", fgYellow, &"'{e.name}' ", fgBlue, "(", fgYellow, $i, fgBlue, ") ===="
styledEcho fgGreen, "\t- Start offset: ", fgYellow, $e.start
styledEcho fgGreen, "\t- End offset: ", fgYellow, $e.stop
styledEcho fgGreen, "\t- Frame bottom: ", fgYellow, $e.bottom
styledEcho fgGreen, "\t- Argument count: ", fgYellow, $e.argc
@ -217,7 +216,7 @@ proc disassembleInstruction*(self: Debugger) =
proc parseCFIData(self: Debugger) =
## Parses CFI information in the chunk
var
start, stop, bottom, argc: int
start, stop, argc: int
name: string
idx = 0
size = 0
@ -226,15 +225,13 @@ proc parseCFIData(self: Debugger) =
idx += 3
stop = int([self.chunk.cfi[idx], self.chunk.cfi[idx + 1], self.chunk.cfi[idx + 2]].fromTriple())
idx += 3
bottom = int([self.chunk.cfi[idx], self.chunk.cfi[idx + 1], self.chunk.cfi[idx + 2]].fromTriple())
idx += 3
argc = int(self.chunk.cfi[idx])
inc(idx)
size = int([self.chunk.cfi[idx], self.chunk.cfi[idx + 1]].fromDouble())
idx += 2
name = self.chunk.cfi[idx..<idx + size].fromBytes()
inc(idx, size)
self.cfiData.add(CFIElement(start: start, stop: stop, bottom: bottom,
self.cfiData.add(CFIElement(start: start, stop: stop,
argc: argc, name: name))