Removed makefile + minor fixes

This commit is contained in:
Mattia Giambirtone 2022-10-11 09:07:25 +02:00
parent 3e6e9da475
commit 15f3143599
2 changed files with 41 additions and 30 deletions

View File

@ -1,5 +0,0 @@
repl:
nim --hints:off --warnings:off r src/main.nim
pretty:
nimpretty src/*.nim src/backend/*.nim src/frontend/*.nim src/frontend/meta/*.nim src/memory/*.nim src/util/*.nim

View File

@ -57,7 +57,7 @@ type
closures: seq[uint64] # Stores closure offsets closures: seq[uint64] # Stores closure offsets
envs: seq[uint64] # Stores variables that do not have stack semantics envs: seq[uint64] # Stores variables that do not have stack semantics
results: seq[uint64] # Stores function's results (return values) results: seq[uint64] # Stores function's results (return values)
gc: PeonGC gc: PeonGC # Our memory manager
ObjectKind* = enum ObjectKind* = enum
## A tag for heap-allocated ## A tag for heap-allocated
## peon objects ## peon objects
@ -77,7 +77,10 @@ type
discard # TODO discard # TODO
PeonGC* = ref object PeonGC* = ref object
## A simple Mark&Sweep collector ## A simple Mark&Sweep collector
## to manage peon's heap space ## to manage peon's heap space.
## All heap allocation goes through
## this system and is not handled
## manually by the VM
vm: PeonVM vm: PeonVM
bytesAllocated: tuple[total, current: int] bytesAllocated: tuple[total, current: int]
nextGC: int nextGC: int
@ -155,7 +158,7 @@ template free*(self: PeonGC, kind: typedesc, p: pointer): untyped =
proc allocate*(self: PeonGC, kind: ObjectKind, size: typedesc, count: int): ptr HeapObject {.inline.} = proc allocate*(self: PeonGC, kind: ObjectKind, size: typedesc, count: int): ptr HeapObject {.inline.} =
## Allocates aobject on the heap ## Allocates aobject on the heap
result = cast[ptr HeapObject](self.reallocate(nil, 0, sizeof(HeapObject) * 1)) result = cast[ptr HeapObject](self.reallocate(nil, 0, sizeof(HeapObject)))
result.marked = false result.marked = false
self.bytesAllocated.total += sizeof(result) self.bytesAllocated.total += sizeof(result)
self.bytesAllocated.current += sizeof(result) self.bytesAllocated.current += sizeof(result)
@ -182,7 +185,8 @@ proc markRoots(self: PeonGC): seq[ptr HeapObject] =
## Marks root objects *not* to be ## Marks root objects *not* to be
## collected by the GC and returns ## collected by the GC and returns
## their addresses ## their addresses
when debugGC:
echo "DEBUG - GC: Starting mark phase"
# Unlike what bob does in his book, # Unlike what bob does in his book,
# we keep track of objects in a different # we keep track of objects in a different
# way due to how the whole thing is designed. # way due to how the whole thing is designed.
@ -204,9 +208,7 @@ proc markRoots(self: PeonGC): seq[ptr HeapObject] =
# we allocated and that would cause a memory leak, but # we allocated and that would cause a memory leak, but
# with a 64-bit address-space it probably hardly matters, # with a 64-bit address-space it probably hardly matters,
# so I guess this is a mostly-precise Mark&Sweep collector # so I guess this is a mostly-precise Mark&Sweep collector
when debugGC: var live = initHashSet[uint64](self.pointers.len())
echo "DEBUG - GC: Starting mark phase"
var live = initHashSet[uint64]()
for obj in self.vm.calls: for obj in self.vm.calls:
if obj in self.pointers: if obj in self.pointers:
live.incl(obj) live.incl(obj)
@ -223,7 +225,7 @@ proc markRoots(self: PeonGC): seq[ptr HeapObject] =
obj = cast[ptr HeapObject](p) obj = cast[ptr HeapObject](p)
if obj.mark(): if obj.mark():
when debugGC: when debugGC:
echo &"DEBUG - GC: Marking object: {obj[]}" echo &"DEBUG - GC: Marked object: {obj[]}"
result.add(obj) result.add(obj)
when debugGC: when debugGC:
echo "DEBUG - GC: Mark phase complete" echo "DEBUG - GC: Mark phase complete"
@ -277,21 +279,21 @@ proc sweep(self: PeonGC) =
## nim disallows changing the ## nim disallows changing the
## size of a sequence during ## size of a sequence during
## iteration ## iteration
when debugGC: when debugGC:
echo "DEBUG - GC: Beginning sweeping phase" echo "DEBUG - GC: Beginning sweeping phase"
var j = -1 var j = -1
var idx = 0 var idx = 0
var count = 0 when debugGC:
var count = 0
while j < self.objects.high(): while j < self.objects.high():
inc(j) inc(j)
if self.objects[j].marked: if self.objects[j].marked:
# Object is marked: don't touch it, # Object is marked: don't touch it,
# but reset its mark so that it doesn't # but reset its mark so that it doesn't
# stay alive forever # stay alive forever
self.objects[j].marked = false
when debugGC: when debugGC:
echo &"DEBUG - GC: Unmarking object: {self.objects[j][]}" echo &"DEBUG - GC: Unmarking object: {self.objects[j][]}"
self.objects[j].marked = false
inc(idx) inc(idx)
else: else:
# Object is unmarked: its memory is # Object is unmarked: its memory is
@ -299,7 +301,8 @@ proc sweep(self: PeonGC) =
self.free(self.objects[idx]) self.free(self.objects[idx])
self.objects.delete(idx) self.objects.delete(idx)
inc(idx) inc(idx)
inc(count) when debugGC:
inc(count)
when debugGC: when debugGC:
echo &"DEBUG - GC: Swept {count} objects" echo &"DEBUG - GC: Swept {count} objects"
@ -308,9 +311,9 @@ proc collect(self: PeonGC) =
## Attempts to reclaim some ## Attempts to reclaim some
## memory from unreachable ## memory from unreachable
## objects onto the heap ## objects onto the heap
let before {.used.} = self.bytesAllocated.current
let time {.used.} = getMonoTime().ticks().float() / 1_000_000
when debugGC: when debugGC:
let before = self.bytesAllocated.current
let time = getMonoTime().ticks().float() / 1_000_000
echo &"DEBUG - GC: Starting collection cycle at heap size {self.bytesAllocated.current}" echo &"DEBUG - GC: Starting collection cycle at heap size {self.bytesAllocated.current}"
self.trace(self.markRoots()) self.trace(self.markRoots())
self.sweep() self.sweep()
@ -793,14 +796,14 @@ proc dispatch*(self: PeonVM) =
if self.frames.len() == 0: if self.frames.len() == 0:
# End of the program! # End of the program!
return return
self.ip = ret.uInt self.ip = ret.uint
of SetResult: of SetResult:
# Sets the result of the # Sets the result of the
# current function. A Return # current function. A Return
# instruction will pop this # instruction will pop this
# off the results array and # off the results array and
# onto the operand stack when # onto the operand stack when
# the current function exits. # the current function exits
self.results[self.frames.high()] = self.pop() self.results[self.frames.high()] = self.pop()
of StoreVar: of StoreVar:
# Stores the value at the top of the operand stack # Stores the value at the top of the operand stack
@ -813,10 +816,12 @@ proc dispatch*(self: PeonVM) =
else: else:
self.pushc(self.pop()) self.pushc(self.pop())
of LoadClosure: of LoadClosure:
# Loads a closed-over variable onto the # Loads a closed-over variable from the current
# stack # environment onto the operand stack
self.push(self.getClosure(self.readLong().int)) self.push(self.getClosure(self.readLong().int))
of PopClosure: of PopClosure:
# Discards a closed-over variable from the
# current environment
discard self.popClosure(self.readLong().int) discard self.popClosure(self.readLong().int)
of StoreClosure: of StoreClosure:
# Stores/updates the value of a closed-over # Stores/updates the value of a closed-over
@ -824,8 +829,8 @@ proc dispatch*(self: PeonVM) =
let item = self.getc(self.readLong().int) let item = self.getc(self.readLong().int)
self.setClosure(self.readLong().int, item) self.setClosure(self.readLong().int, item)
of LoadVar: of LoadVar:
# Pushes a variable onto the operand # Pushes a variable from the call stack
# stack # onto the operand stack
self.push(self.getc(self.readLong().int)) self.push(self.getc(self.readLong().int))
of NoOp: of NoOp:
# Does nothing # Does nothing
@ -863,32 +868,43 @@ proc dispatch*(self: PeonVM) =
# Relative, backward-jump # Relative, backward-jump
self.ip -= self.readLong() self.ip -= self.readLong()
of JumpIfFalse: of JumpIfFalse:
# Conditional positive jump # Conditional, forward-jump
if not self.peek().bool: if not self.peek().bool:
self.ip += self.readLong() self.ip += self.readLong()
of JumpIfTrue: of JumpIfTrue:
# Conditional positive jump # Conditional (if the top of the stack
# equals true), forward-jump
let ip = self.readLong() let ip = self.readLong()
if self.peek().bool: if self.peek().bool:
self.ip += ip self.ip += ip
of JumpIfFalsePop: of JumpIfFalsePop:
# Conditional (if the top of the stack
# equals false), forward-jump. Always
# pops off the operand stack
let ip = self.readLong() let ip = self.readLong()
if not self.pop().bool: if not self.pop().bool:
self.ip += ip self.ip += ip
of JumpIfFalseOrPop: of JumpIfFalseOrPop:
# Conditional (if the top of the stack
# equals false), forward-jump. Pops off
# the operand stack if the value at the
# top of the operand stack is true
let ip = self.readLong() let ip = self.readLong()
if not self.peek().bool: if not self.peek().bool:
self.ip += ip self.ip += ip
else: else:
discard self.pop() discard self.pop()
# Built-in operations on primitive types. # Built-in operations on primitive types.
# Note: for operations where the order of # Note that, for operations where the order
# the operands matters, we don't need to # of the operands matters, we don't need to
# swap the order of the calls to pop: this # swap the order of the calls to pop: this
# is because operators are handled like peon # is because operators are handled like peon
# functions, which means the arguments are # functions, which means the arguments are
# already reversed on the stack when we # already reversed on the stack when we
# execute the instruction # execute the instruction. The beauty of the
# 2's complement system is that for most integer
# types, we don't need specialized instructions
# to operate on them
of Negate: of Negate:
self.push(uint64(-int64(self.pop()))) self.push(uint64(-int64(self.pop())))
of NegateFloat64: of NegateFloat64: