Reverted variable hoisting and fixed minor issue during name resolution. Updated comments
This commit is contained in:
parent
a706fdad7a
commit
cd853bb140
|
@ -208,19 +208,16 @@ proc markRoots(self: var PeonVM): HashSet[ptr HeapObject] =
|
||||||
# Unlike what Bob does in his book, we keep track
|
# Unlike what Bob does in his book, we keep track
|
||||||
# of objects another way, mainly due to the difference
|
# of objects another way, mainly due to the difference
|
||||||
# of our respective designs. Specifically, our VM only
|
# of our respective designs. Specifically, our VM only
|
||||||
# handles a single type (uint64), while Lox has a stack
|
# handles a single type (uint64) while Lox stores all objects
|
||||||
# of heap-allocated structs (which is convenient, but slow).
|
# in heap-allocated structs (which is convenient, but slow).
|
||||||
# The previous implementation would just store all pointers
|
# What we do is store the pointers to the objects we allocated in
|
||||||
# allocated by us in a hash set and then check if any source
|
# a hash set and then, at collection time, do a set difference
|
||||||
# of roots contained any of the integer values that it was
|
# between the reachable objects and the whole set and discard
|
||||||
# keeping track of, but this meant that if a primitive object's
|
# whatever is left; Unfortunately, this means that if a primitive
|
||||||
# value happened to collide with an active pointer the GC would
|
# object's value happens to collide with an active pointer the GC
|
||||||
# mistakenly assume the object was reachable, potentially leading
|
# will mistakenly assume the object to be reachable, potentially
|
||||||
# to a nasty memory leak. The current implementation uses pointer
|
# leading to a nasty memory leak. Let's just hope a 48+ bit address
|
||||||
# tagging: we know that modern CPUs never use bit 63 in addresses,
|
# space makes this occurrence rare enough not to be a problem
|
||||||
# so if it set we know it cannot be a pointer, and if it is set we
|
|
||||||
# just need to check if it's in our list of active addresses or not.
|
|
||||||
# This should resolve the potential memory leak (hopefully)
|
|
||||||
var result = initHashSet[uint64](self.gc.pointers.len())
|
var result = initHashSet[uint64](self.gc.pointers.len())
|
||||||
for obj in self.calls:
|
for obj in self.calls:
|
||||||
if obj in self.gc.pointers:
|
if obj in self.gc.pointers:
|
||||||
|
@ -691,7 +688,7 @@ proc dispatch*(self: var PeonVM) =
|
||||||
while true:
|
while true:
|
||||||
{.computedgoto.} # https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
{.computedgoto.} # https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
||||||
when debugVM:
|
when debugVM:
|
||||||
if self.ip in self.breakpoints or self.breakpoints.len() == 0 or self.debugNext:
|
if self.ip in self.breakpoints or self.debugNext:
|
||||||
self.debug()
|
self.debug()
|
||||||
instruction = OpCode(self.readByte())
|
instruction = OpCode(self.readByte())
|
||||||
case instruction:
|
case instruction:
|
||||||
|
|
|
@ -341,11 +341,9 @@ proc step*(self: Compiler): ASTNode {.inline.} =
|
||||||
# and can be reused across multiple compilation backends
|
# and can be reused across multiple compilation backends
|
||||||
|
|
||||||
proc resolve*(self: Compiler, name: string): Name =
|
proc resolve*(self: Compiler, name: string): Name =
|
||||||
## Traverses all existing namespaces and returns
|
## Traverses all existing namespaces in reverse order
|
||||||
## the first object with the given name. Returns
|
## and returns the first object with the given name.
|
||||||
## nil when the name can't be found. Note that
|
## Returns nil when the name can't be found
|
||||||
## when a type or function declaration is first
|
|
||||||
## resolved, it is also compiled on-the-fly
|
|
||||||
for obj in reversed(self.names):
|
for obj in reversed(self.names):
|
||||||
if obj.ident.token.lexeme == name:
|
if obj.ident.token.lexeme == name:
|
||||||
if obj.owner.path != self.currentModule.path:
|
if obj.owner.path != self.currentModule.path:
|
||||||
|
@ -361,6 +359,7 @@ proc resolve*(self: Compiler, name: string): Name =
|
||||||
# module and said module has explicitly
|
# module and said module has explicitly
|
||||||
# exported it to us: we can use it
|
# exported it to us: we can use it
|
||||||
result = obj
|
result = obj
|
||||||
|
result.resolved = true
|
||||||
break
|
break
|
||||||
# If the name is public but not exported in
|
# If the name is public but not exported in
|
||||||
# its owner module, then we act as if it's
|
# its owner module, then we act as if it's
|
||||||
|
@ -370,6 +369,7 @@ proc resolve*(self: Compiler, name: string): Name =
|
||||||
# might not want to also have access to C's and D's
|
# might not want to also have access to C's and D's
|
||||||
# names as they might clash with its own stuff)
|
# names as they might clash with its own stuff)
|
||||||
continue
|
continue
|
||||||
|
# We own this name, so we can definitely access it
|
||||||
result = obj
|
result = obj
|
||||||
result.resolved = true
|
result.resolved = true
|
||||||
break
|
break
|
||||||
|
|
|
@ -189,7 +189,7 @@ type
|
||||||
SysClock64, # Pushes the output of a monotonic clock on the stack
|
SysClock64, # Pushes the output of a monotonic clock on the stack
|
||||||
LoadTOS, # Pushes the top of the call stack onto the operand stack
|
LoadTOS, # Pushes the top of the call stack onto the operand stack
|
||||||
DupTop, # Duplicates the top of the operand stack onto the operand stack
|
DupTop, # Duplicates the top of the operand stack onto the operand stack
|
||||||
ReplExit, # Exits the VM immediately, leaving its state intact. Used in the REPL
|
ReplExit, # Exits the VM immediately, leaving its state intact. Used in the REPL
|
||||||
LoadGlobal # Loads a global variable
|
LoadGlobal # Loads a global variable
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ proc compile*(self: BytecodeCompiler, ast: seq[Declaration], file: string, lines
|
||||||
mode: CompileMode = Debug): Chunk
|
mode: CompileMode = Debug): Chunk
|
||||||
proc statement(self: BytecodeCompiler, node: Statement)
|
proc statement(self: BytecodeCompiler, node: Statement)
|
||||||
proc declaration(self: BytecodeCompiler, node: Declaration)
|
proc declaration(self: BytecodeCompiler, node: Declaration)
|
||||||
proc varDecl(self: BytecodeCompiler, node: VarDecl, hoist: bool = false)
|
proc varDecl(self: BytecodeCompiler, node: VarDecl)
|
||||||
proc specialize(self: BytecodeCompiler, typ: Type, args: seq[Expression]): Type {.discardable.}
|
proc specialize(self: BytecodeCompiler, typ: Type, args: seq[Expression]): Type {.discardable.}
|
||||||
proc patchReturnAddress(self: BytecodeCompiler, pos: int)
|
proc patchReturnAddress(self: BytecodeCompiler, pos: int)
|
||||||
proc handleMagicPragma(self: BytecodeCompiler, pragma: Pragma, name: Name)
|
proc handleMagicPragma(self: BytecodeCompiler, pragma: Pragma, name: Name)
|
||||||
|
@ -1864,10 +1864,8 @@ proc statement(self: BytecodeCompiler, node: Statement) =
|
||||||
self.expression(Expression(node))
|
self.expression(Expression(node))
|
||||||
|
|
||||||
|
|
||||||
proc varDecl(self: BytecodeCompiler, node: VarDecl, hoist: bool = false) =
|
proc varDecl(self: BytecodeCompiler, node: VarDecl) =
|
||||||
## Compiles variable declarations
|
## Compiles variable declarations
|
||||||
if node.name.depth == 0 and not hoist:
|
|
||||||
return
|
|
||||||
var typ: Type
|
var typ: Type
|
||||||
# Our parser guarantees that the variable declaration
|
# Our parser guarantees that the variable declaration
|
||||||
# will have a type declaration or a value (or both)
|
# will have a type declaration or a value (or both)
|
||||||
|
@ -2078,9 +2076,6 @@ proc compile*(self: BytecodeCompiler, ast: seq[Declaration], file: string, lines
|
||||||
self.jumps = @[]
|
self.jumps = @[]
|
||||||
let pos = self.beginProgram()
|
let pos = self.beginProgram()
|
||||||
let idx = self.stackIndex
|
let idx = self.stackIndex
|
||||||
for node in ast:
|
|
||||||
if node.kind == varDecl and VarDecl(node).name.depth == 0:
|
|
||||||
self.varDecl(VarDecl(node), hoist=true)
|
|
||||||
self.stackIndex = idx
|
self.stackIndex = idx
|
||||||
while not self.done():
|
while not self.done():
|
||||||
self.declaration(Declaration(self.step()))
|
self.declaration(Declaration(self.step()))
|
||||||
|
|
|
@ -51,7 +51,7 @@ proc getLineEditor: LineEditor =
|
||||||
result.bindHistory(history)
|
result.bindHistory(history)
|
||||||
|
|
||||||
|
|
||||||
proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug) =
|
proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug, breakpoints: seq[uint64] = @[]) =
|
||||||
styledEcho fgMagenta, "Welcome into the peon REPL!"
|
styledEcho fgMagenta, "Welcome into the peon REPL!"
|
||||||
var
|
var
|
||||||
keep = true
|
keep = true
|
||||||
|
@ -136,7 +136,7 @@ proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: Comp
|
||||||
else:
|
else:
|
||||||
styledEcho fgRed, "Corrupted"
|
styledEcho fgRed, "Corrupted"
|
||||||
if not first:
|
if not first:
|
||||||
vm.run(serialized.chunk, repl=true)
|
vm.run(serialized.chunk, repl=true, breakpoints=breakpoints)
|
||||||
first = true
|
first = true
|
||||||
else:
|
else:
|
||||||
vm.resume(serialized.chunk)
|
vm.resume(serialized.chunk)
|
||||||
|
@ -407,7 +407,9 @@ when isMainModule:
|
||||||
else:
|
else:
|
||||||
echo "usage: peon [options] [filename.pn]"
|
echo "usage: peon [options] [filename.pn]"
|
||||||
quit()
|
quit()
|
||||||
|
if breaks.len() == 0 and debugVM:
|
||||||
|
breaks.add(0)
|
||||||
if file == "":
|
if file == "":
|
||||||
repl(warnings, mismatches, mode)
|
repl(warnings, mismatches, mode, breaks)
|
||||||
else:
|
else:
|
||||||
runFile(file, fromString, dump, breaks, dis, warnings, mismatches, mode, run, backend, output)
|
runFile(file, fromString, dump, breaks, dis, warnings, mismatches, mode, run, backend, output)
|
||||||
|
|
Loading…
Reference in New Issue