Removed makefile + minor fixes
This commit is contained in:
parent
3e6e9da475
commit
15f3143599
5
Makefile
5
Makefile
|
@ -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
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue