Fix VM memory allocation optimizations by reducing what we allocate on the heap
This commit is contained in:
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user