Fix VM memory allocation optimizations by reducing what we allocate on the heap
Some checks failed
Build / build (push) Successful in 10m25s
Publish Image / publish (push) Failing after 39s
Test / build (push) Successful in 11m19s

This commit is contained in:
Charles Smith
2024-03-31 20:44:50 -04:00
parent a85dc73954
commit aebbe43999
61 changed files with 383 additions and 370 deletions

View File

@@ -20,17 +20,17 @@ const StackSize = 2048
const GlobalsSize = 65536
const MaxFrames = 1024
var Null = &object.Null{}
var True = &object.Boolean{Value: true}
var False = &object.Boolean{Value: false}
var Null = object.Null{}
var True = object.Boolean{Value: true}
var False = object.Boolean{Value: false}
func isTruthy(obj object.Object) bool {
switch obj := obj.(type) {
case *object.Boolean:
case object.Boolean:
return obj.Value
case *object.Null:
case object.Null:
return false
default:
@@ -38,7 +38,7 @@ func isTruthy(obj object.Object) bool {
}
}
// executeModule compiles the named module and returns a *object.Module object
// executeModule compiles the named module and returns a object.Module object
func executeModule(name string, state *VMState) (object.Object, error) {
filename := utils.FindModule(name)
if filename == "" {
@@ -104,7 +104,7 @@ func (s *VMState) ExportedHash() *object.Hash {
if unicode.IsUpper(rune(name[0])) {
if symbol.Scope == compiler.GlobalScope {
obj := s.Globals[symbol.Index]
s := &object.String{Value: name}
s := object.String{Value: name}
pairs[s.HashKey()] = object.HashPair{Key: s, Value: obj}
}
}
@@ -123,20 +123,21 @@ type VM struct {
stack []object.Object
sp int // Always points to the next value. Top of stack is stack[sp-1]
frames []*Frame
frame *Frame // Current frame or nil
fp int // Always points to the current frame. Current frame is frames[fp-1]
frames []Frame
fp int // Always points to the current frame. Current frame is frames[fp-1]
}
func (vm *VM) pushFrame(f *Frame) {
vm.frame = f
func (vm *VM) currentFrame() *Frame {
return &vm.frames[vm.fp-1]
}
func (vm *VM) pushFrame(f Frame) {
vm.frames[vm.fp] = f
vm.fp++
}
func (vm *VM) popFrame() *Frame {
func (vm *VM) popFrame() Frame {
vm.fp--
vm.frame = vm.frames[vm.fp-1]
return vm.frames[vm.fp]
}
@@ -146,7 +147,7 @@ func New(fn string, bytecode *compiler.Bytecode) *VM {
mainClosure := &object.Closure{Fn: mainFn}
mainFrame := NewFrame(mainClosure, 0)
frames := make([]*Frame, MaxFrames)
frames := make([]Frame, MaxFrames)
frames[0] = mainFrame
state := NewVMState()
@@ -159,7 +160,6 @@ func New(fn string, bytecode *compiler.Bytecode) *VM {
sp: 0,
frames: frames,
frame: mainFrame,
fp: 1,
}
@@ -173,14 +173,13 @@ func NewWithState(fn string, bytecode *compiler.Bytecode, state *VMState) *VM {
mainClosure := &object.Closure{Fn: mainFn}
mainFrame := NewFrame(mainClosure, 0)
frames := make([]*Frame, MaxFrames)
frames := make([]Frame, MaxFrames)
frames[0] = mainFrame
vm := &VM{
state: state,
frames: frames,
frame: mainFrame,
fp: 1,
stack: make([]object.Object, StackSize),
@@ -210,30 +209,30 @@ func (vm *VM) pop() object.Object {
}
func (vm *VM) executeLoadBuiltin() error {
builtinIndex := vm.frame.ReadUint8()
builtinIndex := vm.currentFrame().ReadUint8()
builtin := builtins.BuiltinsIndex[builtinIndex]
return vm.push(builtin)
}
func (vm *VM) executeConstant() error {
constIndex := vm.frame.ReadUint16()
constIndex := vm.currentFrame().ReadUint16()
return vm.push(vm.state.Constants[constIndex])
}
func (vm *VM) executeAssignGlobal() error {
globalIndex := vm.frame.ReadUint16()
globalIndex := vm.currentFrame().ReadUint16()
vm.state.Globals[globalIndex] = vm.pop()
return vm.push(Null)
}
func (vm *VM) executeAssignLocal() error {
localIndex := vm.frame.ReadUint8()
vm.stack[vm.frame.basePointer+int(localIndex)] = vm.pop()
localIndex := vm.currentFrame().ReadUint8()
vm.stack[vm.currentFrame().basePointer+int(localIndex)] = vm.pop()
return vm.push(Null)
}
func (vm *VM) executeSetGlobal() error {
globalIndex := vm.frame.ReadUint16()
globalIndex := vm.currentFrame().ReadUint16()
ref := vm.pop()
if immutable, ok := ref.(object.Immutable); ok {
@@ -246,31 +245,31 @@ func (vm *VM) executeSetGlobal() error {
}
func (vm *VM) executeGetGlobal() error {
globalIndex := vm.frame.ReadUint16()
globalIndex := vm.currentFrame().ReadUint16()
return vm.push(vm.state.Globals[globalIndex])
}
func (vm *VM) executeSetLocal() error {
localIndex := vm.frame.ReadUint8()
localIndex := vm.currentFrame().ReadUint8()
ref := vm.pop()
if immutable, ok := ref.(object.Immutable); ok {
vm.stack[vm.frame.basePointer+int(localIndex)] = immutable.Clone()
vm.stack[vm.currentFrame().basePointer+int(localIndex)] = immutable.Clone()
} else {
vm.stack[vm.frame.basePointer+int(localIndex)] = ref
vm.stack[vm.currentFrame().basePointer+int(localIndex)] = ref
}
return vm.push(Null)
}
func (vm *VM) executeGetLocal() error {
localIndex := vm.frame.ReadUint8()
return vm.push(vm.stack[vm.frame.basePointer+int(localIndex)])
localIndex := vm.currentFrame().ReadUint8()
return vm.push(vm.stack[vm.currentFrame().basePointer+int(localIndex)])
}
func (vm *VM) executeGetFree() error {
freeIndex := vm.frame.ReadUint8()
return vm.push(vm.frame.cl.Free[freeIndex])
freeIndex := vm.currentFrame().ReadUint8()
return vm.push(vm.currentFrame().GetFree(freeIndex))
}
func (vm *VM) executeLoadModule() error {
@@ -279,7 +278,7 @@ func (vm *VM) executeLoadModule() error {
}
func (vm *VM) executeCurrentClosure() error {
currentClosure := vm.frame.cl
currentClosure := vm.currentFrame().cl
return vm.push(currentClosure)
}
@@ -316,7 +315,7 @@ func (vm *VM) buildHash(startIndex, endIndex int) (object.Object, error) {
}
func (vm *VM) executeMakeHash() error {
startIndex := vm.sp - int(vm.frame.ReadUint16())
startIndex := vm.sp - int(vm.currentFrame().ReadUint16())
hash, err := vm.buildHash(startIndex, vm.sp)
if err != nil {
return err
@@ -336,7 +335,7 @@ func (vm *VM) buildArray(startIndex, endIndex int) (object.Object, error) {
}
func (vm *VM) executeMakeArray() error {
startIndex := vm.sp - int(vm.frame.ReadUint16())
startIndex := vm.sp - int(vm.currentFrame().ReadUint16())
hash, err := vm.buildArray(startIndex, vm.sp)
if err != nil {
return err
@@ -346,8 +345,8 @@ func (vm *VM) executeMakeArray() error {
}
func (vm *VM) executeClosure() error {
constIndex := vm.frame.ReadUint16()
numFree := vm.frame.ReadUint8()
constIndex := vm.currentFrame().ReadUint16()
numFree := vm.currentFrame().ReadUint8()
return vm.pushClosure(int(constIndex), int(numFree))
}
@@ -659,7 +658,7 @@ func (vm *VM) executeGetItem() error {
}
func (vm *VM) executeCall() error {
args := int(vm.frame.ReadUint8())
args := int(vm.currentFrame().ReadUint8())
callee := vm.stack[vm.sp-1-args]
switch callee := callee.(type) {
@@ -685,16 +684,16 @@ func (vm *VM) executeReturn() error {
}
func (vm *VM) executeJumpIfFalse() error {
pos := int(vm.frame.ReadUint16())
pos := int(vm.currentFrame().ReadUint16())
if !isTruthy(vm.pop()) {
vm.frame.ip = pos
vm.currentFrame().SetIP(pos)
}
return nil
}
func (vm *VM) executeJump() error {
pos := int(vm.frame.ReadUint16())
vm.frame.ip = pos
pos := int(vm.currentFrame().ReadUint16())
vm.currentFrame().SetIP(pos)
return nil
}
@@ -709,14 +708,14 @@ func (vm *VM) callClosure(cl *object.Closure, numArgs int) error {
}
// Optimize tail calls and avoid a new frame
if cl.Fn == vm.frame.cl.Fn {
nextOP := vm.frame.PeekNextOp()
if cl.Fn == vm.currentFrame().cl.Fn {
nextOP := vm.currentFrame().PeekNextOp()
if nextOP == code.OpReturn {
for p := 0; p < numArgs; p++ {
vm.stack[vm.frame.basePointer+p] = vm.stack[vm.sp-numArgs+p]
vm.stack[vm.currentFrame().basePointer+p] = vm.stack[vm.sp-numArgs+p]
}
vm.sp -= numArgs + 1
vm.frame.ip = 0 // reset IP to the beginning of the frame
vm.currentFrame().SetIP(0) // reset IP to the beginning of the frame
return nil
}
}
@@ -767,7 +766,7 @@ func (vm *VM) pushClosure(constIndex, numFree int) error {
}
func (vm *VM) loadModule(name object.Object) error {
s, ok := name.(*object.String)
s, ok := name.(object.String)
if !ok {
return fmt.Errorf(
"TypeError: import() expected argument #1 to be `str` got `%s`",
@@ -780,7 +779,7 @@ func (vm *VM) loadModule(name object.Object) error {
return err
}
module := &object.Module{Name: s.Value, Attrs: attrs}
module := object.Module{Name: s.Value, Attrs: attrs}
return vm.push(module)
}
@@ -799,16 +798,16 @@ func (vm *VM) Run() (err error) {
}
for err == nil {
op := vm.frame.ReadNextOp()
op := vm.currentFrame().ReadNextOp()
if vm.Debug {
n++
log.Printf(
"%-25s %-20s\n",
fmt.Sprintf("%04d %s", vm.frame.ip, op),
fmt.Sprintf("%04d %s", vm.currentFrame().ip, op),
fmt.Sprintf(
"[ip=%02d fp=%02d, sp=%02d]",
vm.frame.ip, vm.fp-1, vm.sp,
vm.currentFrame().ip, vm.fp-1, vm.sp,
),
)
}
@@ -953,7 +952,7 @@ func (vm *VM) Run() (err error) {
if vm.Debug {
log.Printf(
"%-25s [ip=%02d fp=%02d, sp=%02d]",
"", vm.frame.ip, vm.fp-1, vm.sp,
"", vm.currentFrame().ip, vm.fp-1, vm.sp,
)
}
}