Definitive fix for closures

This commit is contained in:
Mattia Giambirtone 2022-10-08 09:18:35 +02:00
parent fc74bab529
commit 11c8c0a5ab
3 changed files with 20 additions and 19 deletions

View File

@ -31,7 +31,7 @@ when debugVM or debugMem or debugGC:
import std/terminal import std/terminal
{.push checks:off.} # The VM is a critical point where checks are deleterious {.push checks:on.} # The VM is a critical point where checks are deleterious
type type
PeonVM* = ref object PeonVM* = ref object

View File

@ -188,7 +188,7 @@ type
# Stores the position of all jumps # Stores the position of all jumps
jumps: seq[tuple[patched: bool, offset: int]] jumps: seq[tuple[patched: bool, offset: int]]
# List of CFI start offsets into our CFI data # List of CFI start offsets into our CFI data
cfiOffsets: seq[tuple[value, offset: int, fn: Name]] cfiOffsets: seq[tuple[start, stop: int, fn: Name]]
CompileError* = ref object of PeonException CompileError* = ref object of PeonException
compiler*: Compiler compiler*: Compiler
node*: ASTNode node*: ASTNode
@ -416,18 +416,20 @@ proc fixCFIOffsets(self: Compiler, oldLen: int, modifiedAt: int) =
let offset = self.chunk.code.len() - oldLen let offset = self.chunk.code.len() - oldLen
var newCFI: array[3, uint8] var newCFI: array[3, uint8]
var tmp: int var tmp: int
for cfi in self.cfiOffsets: for cfi in self.cfiOffsets.mitems():
if cfi.offset >= modifiedAt: if cfi.start >= modifiedAt:
newCFI = (cfi.value + offset).toTriple() newCFI = (cfi.start + offset).toTriple()
self.chunk.cfi[cfi.offset] = newCFI[0] self.chunk.cfi[cfi.start] = newCFI[0]
self.chunk.cfi[cfi.offset + 1] = newCFI[1] self.chunk.cfi[cfi.start + 1] = newCFI[1]
self.chunk.cfi[cfi.offset + 2] = newCFI[2] self.chunk.cfi[cfi.start + 2] = newCFI[2]
tmp = [self.chunk.cfi[cfi.offset + 3], self.chunk.cfi[cfi.offset + 4], self.chunk.cfi[cfi.offset + 5]].fromTriple().int tmp = [self.chunk.cfi[cfi.start + 3], self.chunk.cfi[cfi.start + 4], self.chunk.cfi[cfi.start + 5]].fromTriple().int
newCFI = (tmp + offset).toTriple() newCFI = (tmp + offset).toTriple()
self.chunk.cfi[cfi.offset + 3] = newCFI[0] self.chunk.cfi[cfi.start + 3] = newCFI[0]
self.chunk.cfi[cfi.offset + 4] = newCFI[1] self.chunk.cfi[cfi.start + 4] = newCFI[1]
self.chunk.cfi[cfi.offset + 5] = newCFI[2] self.chunk.cfi[cfi.start + 5] = newCFI[2]
cfi.fn.codePos += offset cfi.fn.codePos += offset
cfi.start += offset
cfi.stop += offset
proc fixJumps(self: Compiler, oldLen: int, modifiedAt: int) = proc fixJumps(self: Compiler, oldLen: int, modifiedAt: int) =
@ -444,8 +446,7 @@ proc fixJumps(self: Compiler, oldLen: int, modifiedAt: int) =
# list in cases where we shifted the jump # list in cases where we shifted the jump
# instruction itself into the code! # instruction itself into the code!
jump.offset += offset jump.offset += offset
if jump.patched: self.setJump(jump.offset, self.chunk.code[jump.offset + 1..jump.offset + 3])
self.setJump(jump.offset, self.chunk.code[jump.offset..<jump.offset + 3])
proc resolve(self: Compiler, name: IdentExpr, proc resolve(self: Compiler, name: IdentExpr,
@ -1899,14 +1900,11 @@ proc typeDecl(self: Compiler, node: TypeDecl) =
proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression] = @[]) = proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression] = @[]) =
## Compiles function declarations ## Compiles function declarations
# A function's code is just compiled linearly
# and then jumped over
if node.token.kind == Operator and node.token.lexeme in [".", ]: if node.token.kind == Operator and node.token.lexeme in [".", ]:
self.error(&"The '{node.token.lexeme}' cannot be overridden", node) self.error(&"The '{node.token.lexeme}' cannot be overridden", node)
var jmp: int var jmp: int
self.declareName(node) self.declareName(node)
self.dispatchPragmas(node) self.dispatchPragmas(node)
# Function's code starts after the jump
var node = node var node = node
var fn = if fn.isNil(): self.names[^(node.arguments.len() + 1)] else: fn var fn = if fn.isNil(): self.names[^(node.arguments.len() + 1)] else: fn
# We store the current function # We store the current function
@ -1915,7 +1913,6 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
self.currentFunction.valueType.children.add(fn.valueType) self.currentFunction.valueType.children.add(fn.valueType)
fn.valueType.parent = function.valueType fn.valueType.parent = function.valueType
self.currentFunction = fn self.currentFunction = fn
var names {.used.} = self.names[^(node.arguments.len())..^1]
if fn.valueType.isBuiltinFunction: if fn.valueType.isBuiltinFunction:
fn.codePos = self.chunk.code.len() fn.codePos = self.chunk.code.len()
# We take the arguments off of our name list # We take the arguments off of our name list
@ -1927,11 +1924,13 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
# can only be relatively simple # can only be relatively simple
self.names = self.names[0..^node.arguments.len() + 1] self.names = self.names[0..^node.arguments.len() + 1]
elif not node.body.isNil(): elif not node.body.isNil():
# A function's code is just compiled linearly
# and then jumped over
jmp = self.emitJump(JumpForwards, node.token.line) jmp = self.emitJump(JumpForwards, node.token.line)
fn.codePos = self.chunk.code.len() fn.codePos = self.chunk.code.len()
# We let our debugger know this function's boundaries # We let our debugger know this function's boundaries
self.chunk.cfi.add(self.chunk.code.high().toTriple()) self.chunk.cfi.add(self.chunk.code.high().toTriple())
self.cfiOffsets.add((value: self.chunk.code.high(), offset: self.chunk.cfi.high() - 2, fn: fn)) self.cfiOffsets.add((start: self.chunk.code.high(), stop: 0, fn: fn))
let idx = self.chunk.cfi.len() let idx = self.chunk.cfi.len()
self.chunk.cfi.add(0.toTriple()) # Patched it later self.chunk.cfi.add(0.toTriple()) # Patched it later
self.chunk.cfi.add(uint8(node.arguments.len())) self.chunk.cfi.add(uint8(node.arguments.len()))
@ -1985,6 +1984,7 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
self.chunk.cfi[idx] = stop[0] self.chunk.cfi[idx] = stop[0]
self.chunk.cfi[idx + 1] = stop[1] self.chunk.cfi[idx + 1] = stop[1]
self.chunk.cfi[idx + 2] = stop[2] self.chunk.cfi[idx + 2] = stop[2]
self.cfiOffsets[^1].stop = self.chunk.code.len()
# Currently defer is not functional, so we # Currently defer is not functional, so we
# just pop the instructions # just pop the instructions
for _ in deferStart..self.deferred.high(): for _ in deferStart..self.deferred.high():

View File

@ -2,6 +2,7 @@
import std; import std;
fn makeClosure(n: int): fn: fn: int { fn makeClosure(n: int): fn: fn: int {
fn inner: fn: int { fn inner: fn: int {
fn deep: int { fn deep: int {