optimizations
Some checks failed
Build / build (push) Successful in 10m29s
Publish Image / publish (push) Failing after 31s
Test / build (push) Failing after 6m34s

This commit is contained in:
Chuck Smith
2024-04-02 14:08:08 -04:00
parent 4c9ec5aaaa
commit 07fd82b261
23 changed files with 296 additions and 265 deletions

View File

@@ -2,7 +2,6 @@ package vm
import (
"fmt"
"log"
"monkey/internal/builtins"
"monkey/internal/code"
"monkey/internal/compiler"
@@ -13,8 +12,6 @@ import (
"monkey/internal/utils"
"os"
"path/filepath"
"sort"
"time"
"unicode"
)
@@ -151,20 +148,25 @@ func (vm *VM) popFrame() frame {
return vm.frames[vm.fp]
}
// Option defines a function option for the virtual machine.
type Option func(*VM)
// WithContext defines an option to set the context for the virtual machine.
func WithContext(ctx context.Context) Option {
return func(vm *VM) { vm.ctx = ctx }
}
// WithDebug enables debug mode in the VM.
func WithDebug(debug bool) Option {
return func(vm *VM) { vm.debug = debug }
}
// WithState sets the state of the VM.
func WithState(state *State) Option {
return func(vm *VM) { vm.state = state }
}
// WithTrace sets the trace flag for the VM.
func WithTrace(trace bool) Option {
return func(vm *VM) { vm.trace = trace }
}
@@ -224,6 +226,29 @@ func (vm *VM) pop() object.Object {
return o
}
func (vm *VM) pop2() (object.Object, object.Object) {
if vm.sp == 1 {
panic("stack underflow")
}
o1 := vm.stack[vm.sp-1]
o2 := vm.stack[vm.sp-2]
vm.sp -= 2
return o1, o2
}
func (vm *VM) pop3() (object.Object, object.Object, object.Object) {
if vm.sp == 2 {
panic("stack underflow")
}
o1 := vm.stack[vm.sp-1]
o2 := vm.stack[vm.sp-2]
o3 := vm.stack[vm.sp-3]
vm.sp -= 3
return o1, o2, o3
}
func (vm *VM) executeSetGlobal() error {
globalIndex := vm.currentFrame().ReadUint16()
@@ -301,8 +326,7 @@ func (vm *VM) executeMakeArray() error {
}
func (vm *VM) executeAdd() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -335,8 +359,7 @@ func (vm *VM) executeAdd() error {
}
func (vm *VM) executeSub() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -351,8 +374,7 @@ func (vm *VM) executeSub() error {
}
func (vm *VM) executeMul() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case *object.Array:
@@ -379,8 +401,7 @@ func (vm *VM) executeMul() error {
}
func (vm *VM) executeDiv() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -396,8 +417,7 @@ func (vm *VM) executeDiv() error {
}
func (vm *VM) executeMod() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -412,8 +432,7 @@ func (vm *VM) executeMod() error {
}
func (vm *VM) executeOr() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Boolean:
@@ -428,8 +447,7 @@ func (vm *VM) executeOr() error {
}
func (vm *VM) executeAnd() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Boolean:
@@ -444,8 +462,7 @@ func (vm *VM) executeAnd() error {
}
func (vm *VM) executeBitwiseOr() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -460,8 +477,7 @@ func (vm *VM) executeBitwiseOr() error {
}
func (vm *VM) executeBitwiseXor() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -476,8 +492,7 @@ func (vm *VM) executeBitwiseXor() error {
}
func (vm *VM) executeBitwiseAnd() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -503,8 +518,7 @@ func (vm *VM) executeBitwiseNot() error {
}
func (vm *VM) executeLeftShift() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -519,8 +533,7 @@ func (vm *VM) executeLeftShift() error {
}
func (vm *VM) executeRightShift() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
switch obj := left.(type) {
case object.Integer:
@@ -535,63 +548,39 @@ func (vm *VM) executeRightShift() error {
}
func (vm *VM) executeEqual() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
if obj, ok := left.(object.Comparable); ok {
val := obj.Compare(right)
if val == 0 {
return vm.push(object.TRUE)
}
return vm.push(object.FALSE)
if left.Compare(right) == 0 {
return vm.push(object.TRUE)
}
return object.NewBinaryOpError(left, right, "==")
return vm.push(object.FALSE)
}
func (vm *VM) executeNotEqual() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
if obj, ok := left.(object.Comparable); ok {
val := obj.Compare(right)
if val != 0 {
return vm.push(object.TRUE)
}
return vm.push(object.FALSE)
if left.Compare(right) != 0 {
return vm.push(object.TRUE)
}
return object.NewBinaryOpError(left, right, "!=")
return vm.push(object.FALSE)
}
func (vm *VM) executeGreaterThan() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
if obj, ok := left.(object.Comparable); ok {
val := obj.Compare(right)
if val == 1 {
return vm.push(object.TRUE)
}
return vm.push(object.FALSE)
if left.Compare(right) == 1 {
return vm.push(object.TRUE)
}
return object.NewBinaryOpError(left, right, ">")
return vm.push(object.FALSE)
}
func (vm *VM) executeGreaterThanOrEqual() error {
right := vm.pop()
left := vm.pop()
right, left := vm.pop2()
if obj, ok := left.(object.Comparable); ok {
val := obj.Compare(right)
if val >= 0 {
return vm.push(object.TRUE)
}
return vm.push(object.FALSE)
if left.Compare(right) == 1 {
return vm.push(object.TRUE)
}
return object.NewBinaryOpError(left, right, ">")
return vm.push(object.FALSE)
}
func (vm *VM) executeNot() error {
@@ -621,9 +610,7 @@ func (vm *VM) executeMinus() error {
}
func (vm *VM) executeSetItem() error {
right := vm.pop()
index := vm.pop()
left := vm.pop()
right, index, left := vm.pop3()
switch obj := left.(type) {
case *object.Array:
@@ -647,8 +634,7 @@ func (vm *VM) executeSetItem() error {
}
func (vm *VM) executeGetItem() error {
index := vm.pop()
left := vm.pop()
index, left := vm.pop2()
switch obj := left.(type) {
case object.String:
@@ -749,7 +735,7 @@ func (vm *VM) pushClosure(constIndex, numFree int) error {
for i := 0; i < numFree; i++ {
free[i] = vm.stack[vm.sp-numFree+i]
}
vm.sp = vm.sp - numFree
vm.sp -= numFree
closure := object.Closure{Fn: function, Free: free}
return vm.push(&closure)
@@ -778,49 +764,9 @@ func (vm *VM) LastPoppedStackElem() object.Object {
}
func (vm *VM) Run() (err error) {
var (
op code.Opcode
opcodeFreqs = make(map[code.Opcode]int)
)
if vm.debug {
start := time.Now()
defer func() {
end := time.Now().Sub(start)
total := 0
opcodes := make([]code.Opcode, 0, len(opcodeFreqs))
for opcode, count := range opcodeFreqs {
opcodes = append(opcodes, opcode)
total += count
}
sort.SliceStable(opcodes, func(i, j int) bool {
return opcodeFreqs[opcodes[i]] > opcodeFreqs[opcodes[j]]
})
log.Printf("%d instructions executed in %s %d/µs", total, end, total/int(end.Microseconds()))
log.Print("Top Instructions:")
for _, opcode := range opcodes[:min(len(opcodes), 10)] {
log.Printf("%10d %s", opcodeFreqs[opcode], opcode)
}
}()
}
for err == nil {
op = vm.currentFrame().ReadNextOp()
if vm.debug {
opcodeFreqs[op]++
log.Printf(
"%-25s %-20s\n",
fmt.Sprintf("%04d %s", vm.currentFrame().ip, op),
fmt.Sprintf(
"[ip=%02d fp=%02d, sp=%02d]",
vm.currentFrame().ip, vm.fp-1, vm.sp,
),
)
}
op := vm.currentFrame().ReadNextOp()
switch op {
case code.OpConstant:
@@ -837,11 +783,11 @@ func (vm *VM) Run() (err error) {
err = vm.push(object.FALSE)
case code.OpJump:
pos := int(vm.currentFrame().ReadUint16())
pos := vm.currentFrame().ReadUint16()
vm.currentFrame().SetIP(pos)
case code.OpJumpNotTruthy:
pos := int(vm.currentFrame().ReadUint16())
pos := vm.currentFrame().ReadUint16()
if !isTruthy(vm.pop()) {
vm.currentFrame().SetIP(pos)
}
@@ -979,14 +925,7 @@ func (vm *VM) Run() (err error) {
default:
err = fmt.Errorf("unhandled opcode: %s", op)
}
if vm.trace {
log.Printf(
"%-25s [ip=%02d fp=%02d, sp=%02d]",
"", vm.currentFrame().ip, vm.fp-1, vm.sp,
)
}
}
return err
return
}