Skip to content

Commit

Permalink
allow to reuse vm
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Apr 19, 2020
1 parent 637431e commit d676309
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 28 deletions.
54 changes: 54 additions & 0 deletions bench_test.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions cmd/exe/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func debugger() {
program, err := compiler.Compile(tree, nil)
check(err)

vm := NewVM(true)
vm := Debug()

app := tview.NewApplication()
table := tview.NewTable()
Expand All @@ -54,7 +54,7 @@ func debugger() {
app.SetRoot(flex, true)

go func() {
out := vm.Run(program, nil)
out, _ := vm.Run(program, nil)
app.QueueUpdateDraw(func() {
sub.RemoveItem(scope)
result := tview.NewTextView()
Expand Down
37 changes: 37 additions & 0 deletions docs/Optimizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,41 @@ Will be replaced with result of `fib(42)` on compile step. No need to calculate

[ConstExpr Example](https://pkg.go.dev/github.com/antonmedv/expr?tab=doc#ConstExpr)

## Reuse VM

It is possible to reuse a virtual machine between re-runs on the program.
This adds a small increase in performance (from 4% to 40% depending on a program).

```go
package main

import (
"fmt"
"github.com/antonmedv/expr"
"github.com/antonmedv/expr/vm"
)

func main() {
env := map[string]interface{}{
"foo": 1,
"bar": 2,
}

program, err := expr.Compile("foo + bar", expr.Env(env))
if err != nil {
panic(err)
}

// Reuse this vm instance between runs
v := vm.VM{}

out, err := v.Run(program, env)
if err != nil {
panic(err)
}

fmt.Print(out)
}
```

* [Contents](README.md)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
Expand All @@ -11,6 +13,7 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498 h1:4CFNy7/q7P06AsIONZzuWy7jcdqEmYQvOZ9FAFZdbls=
github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
Expand All @@ -26,7 +29,9 @@ golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
60 changes: 34 additions & 26 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,13 @@ var (
MemoryBudget int = 1e6
)

func Run(program *Program, env interface{}) (out interface{}, err error) {
func Run(program *Program, env interface{}) (interface{}, error) {
if program == nil {
return nil, fmt.Errorf("program is nil")
}

vm := NewVM(false)

defer func() {
if r := recover(); r != nil {
f := &file.Error{
Location: program.Locations[vm.pp],
Message: fmt.Sprintf("%v", r),
}
err = f.Bind(program.Source)
}
}()

out = vm.Run(program, env)
return
vm := VM{}
return vm.Run(program, env)
}

type VM struct {
Expand All @@ -48,20 +36,40 @@ type VM struct {
limit int
}

func NewVM(debug bool) *VM {
func Debug() *VM {
vm := &VM{
stack: make([]interface{}, 0, 2),
debug: debug,
limit: MemoryBudget,
}
if vm.debug {
vm.step = make(chan struct{}, 0)
vm.curr = make(chan int, 0)
debug: true,
step: make(chan struct{}, 0),
curr: make(chan int, 0),
}
return vm
}

func (vm *VM) Run(program *Program, env interface{}) interface{} {
func (vm *VM) Run(program *Program, env interface{}) (out interface{}, err error) {
defer func() {
if r := recover(); r != nil {
f := &file.Error{
Location: program.Locations[vm.pp],
Message: fmt.Sprintf("%v", r),
}
err = f.Bind(program.Source)
}
}()

vm.limit = MemoryBudget
vm.ip = 0
vm.pp = 0

if vm.stack == nil {
vm.stack = make([]interface{}, 0, 2)
} else {
vm.stack = vm.stack[0:0]
}

if vm.scopes != nil {
vm.scopes = vm.scopes[0:0]
}

vm.bytecode = program.Bytecode
vm.constants = program.Constants

Expand Down Expand Up @@ -379,10 +387,10 @@ func (vm *VM) Run(program *Program, env interface{}) interface{} {
}

if len(vm.stack) > 0 {
return vm.pop()
return vm.pop(), nil
}

return nil
return nil, nil
}

func (vm *VM) push(value interface{}) {
Expand Down

0 comments on commit d676309

Please sign in to comment.