Skip to content

Commit

Permalink
Merge pull request #4 from regeda/rm-hard-limits
Browse files Browse the repository at this point in the history
Remove memory hard limits
  • Loading branch information
regeda authored May 6, 2021
2 parents 441486d + b767b17 commit 296d984
Show file tree
Hide file tree
Showing 20 changed files with 239 additions and 366 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,5 @@ equals("foo,bar,baz", join(",", ["foo", "bar", "baz"]))
```
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
BenchmarkExec
BenchmarkExec-8 1746600 673.2 ns/op 0 B/op 0 allocs/op
BenchmarkExec-8 1318488 887.4 ns/op 0 B/op 0 allocs/op
```
18 changes: 9 additions & 9 deletions assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ var (
)

type Asserter interface {
Assert([]*memory.Addr) error
Assert([]memory.Addr) error
}

type AsserterFunc func([]*memory.Addr) error
type AsserterFunc func([]memory.Addr) error

func (a AsserterFunc) Assert(argv []*memory.Addr) error {
func (a AsserterFunc) Assert(argv []memory.Addr) error {
return a(argv)
}

func Len(l int) AsserterFunc {
return func(argv []*memory.Addr) error {
return func(argv []memory.Addr) error {
if len(argv) != l {
return errWrongArgsNumber
}
Expand All @@ -30,7 +30,7 @@ func Len(l int) AsserterFunc {
}

func TypeAt(i int, t memory.Type) AsserterFunc {
return func(argv []*memory.Addr) error {
return func(argv []memory.Addr) error {
if argv[i].Type() != t {
return errWrongArgType
}
Expand All @@ -39,13 +39,13 @@ func TypeAt(i int, t memory.Type) AsserterFunc {
}

func VectorAt(i int, a Asserter) AsserterFunc {
return func(argv []*memory.Addr) error {
return func(argv []memory.Addr) error {
return a.Assert(argv[i].Vector())
}
}

func Type(t memory.Type) AsserterFunc {
return func(argv []*memory.Addr) error {
return func(argv []memory.Addr) error {
for _, arg := range argv {
if arg.Type() != t {
return errWrongArgType
Expand All @@ -56,7 +56,7 @@ func Type(t memory.Type) AsserterFunc {
}

func Any(a ...Asserter) AsserterFunc {
return func(argv []*memory.Addr) error {
return func(argv []memory.Addr) error {
var lastErr error
for _, aa := range a {
err := aa.Assert(argv)
Expand All @@ -70,7 +70,7 @@ func Any(a ...Asserter) AsserterFunc {
}

func Every(a ...Asserter) AsserterFunc {
return func(argv []*memory.Addr) error {
return func(argv []memory.Addr) error {
for _, aa := range a {
if err := aa.Assert(argv); err != nil {
return err
Expand Down
11 changes: 10 additions & 1 deletion bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ import (
"github.com/regeda/expr/exec"
"github.com/regeda/expr/internal/ast/value"
"github.com/regeda/expr/internal/compiler"
"github.com/regeda/expr/memory"
"github.com/regeda/expr/stdlib"
)

func BenchmarkExec(b *testing.B) {
comp := compiler.New()
vm := exec.New(stdlib.Registry())
vm := exec.New(stdlib.Registry(),
exec.WithStackSize(0xff),
exec.WithMemory(
memory.New(
memory.PreallocHeap(0xff),
memory.PreallocGrid(0xff),
),
),
)

bcode := comp.Compile(value.Nest(
value.Exit(),
Expand Down
14 changes: 7 additions & 7 deletions delegate/delegator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import (
)

type Delegator interface {
Delegate(*memory.Memory, []*memory.Addr) (*memory.Addr, error)
Delegate(*memory.Memory, []memory.Addr) (memory.Addr, error)
}

type DelegatorFunc func(*memory.Memory, []*memory.Addr) (*memory.Addr, error)
type DelegatorFunc func(*memory.Memory, []memory.Addr) (memory.Addr, error)

func (f DelegatorFunc) Delegate(memory *memory.Memory, argv []*memory.Addr) (*memory.Addr, error) {
return f(memory, argv)
func (f DelegatorFunc) Delegate(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) {
return f(mem, argv)
}

func (f DelegatorFunc) Assert(a assert.Asserter) DelegatorFunc {
return func(memory *memory.Memory, argv []*memory.Addr) (*memory.Addr, error) {
return func(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) {
if err := a.Assert(argv); err != nil {
return nil, err
return memory.Nil, err
}
return f(memory, argv)
return f(mem, argv)
}
}
35 changes: 10 additions & 25 deletions exec/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,23 @@ import (
"github.com/regeda/expr/memory"
)

const (
stacklimit = 0xff
)

type stack struct {
p uint32
seq [stacklimit]*memory.Addr
}
type stack []memory.Addr

func (s *stack) reset() {
s.p = 0
}

func (s *stack) push(a *memory.Addr) error {
if s.p == uint32(len(s.seq)) {
return errStackOverflow
}
s.seq[s.p] = a
s.p++
return nil
*s = (*s)[:0]
}

func (s *stack) tail(n uint32) bool {
return s.p-n >= 0
func (s *stack) push(a memory.Addr) {
*s = append(*s, a)
}

func (s *stack) pop(n uint32) ([]*memory.Addr, error) {
if !s.tail(n) {
func (s *stack) pop(n uint32) ([]memory.Addr, error) {
l := uint32(len(*s))
if n > l {
return nil, fmt.Errorf("stack tail shorter than %d", n)
}
offset := s.p - n
a := s.seq[offset:s.p]
s.p = offset
offset := l - n
a := (*s)[offset:l]
*s = (*s)[:offset]
return a, nil
}
66 changes: 43 additions & 23 deletions exec/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,30 @@ type VM struct {
prog bytecode.Program
}

func New(delegators map[string]delegate.Delegator) *VM {
return &VM{
type Opt func(*VM)

func WithMemory(m memory.Memory) Opt {
return func(vm *VM) {
vm.memory = m
}
}

func WithStackSize(n uint32) Opt {
return func(vm *VM) {
vm.stack = make(stack, 0, n)
}
}

func New(delegators map[string]delegate.Delegator, opts ...Opt) *VM {
vm := &VM{
delegators: delegators,
}

for _, opt := range opts {
opt(vm)
}

return vm
}

func (v *VM) reset() {
Expand All @@ -47,26 +67,26 @@ func (v *VM) checkVersion() error {
return nil
}

func (v *VM) terminate() (*memory.Addr, error) {
func (v *VM) terminate() (memory.Addr, error) {
val, err := v.stack.pop(1)
if err != nil {
return nil, err
return memory.Nil, err
}
return val[0], nil
}

func (v *VM) Exec(bcode []byte) (*memory.Addr, error) {
func (v *VM) Exec(bcode []byte) (memory.Addr, error) {
v.reset()

v.prog.Init(bcode, flatbuffers.GetUOffsetT(bcode))

if err := v.checkVersion(); err != nil {
return nil, err
return memory.Nil, err
}

framesLen := v.prog.FramesLength()
if framesLen == 0 {
return nil, errNoFrames
return memory.Nil, errNoFrames
}

for i := 0; i < framesLen; i++ {
Expand All @@ -75,23 +95,23 @@ func (v *VM) Exec(bcode []byte) (*memory.Addr, error) {
if err == errOpRet {
return v.terminate()
}
return nil, errors.Wrapf(err, "failed to exec frame at %d", i)
return memory.Nil, errors.Wrapf(err, "failed to exec frame at %d", i)
}
v.stack.push(addr)
}

return nil, errUnexpectedEOP
return memory.Nil, errUnexpectedEOP
}

func (v *VM) execFrame(i int) (*memory.Addr, error) {
func (v *VM) execFrame(i int) (memory.Addr, error) {
var frame bytecode.Frame
if !v.prog.Frames(&frame, i) {
return nil, errUnexpectedEOF
return memory.Nil, errUnexpectedEOF
}

var tab flatbuffers.Table
if !frame.Op(&tab) {
return nil, errNoOperation
return memory.Nil, errNoOperation
}

opType := frame.OpType()
Expand All @@ -100,45 +120,45 @@ func (v *VM) execFrame(i int) (*memory.Addr, error) {
var op bytecode.OpPushBool
op.Init(tab.Bytes, tab.Pos)
if op.Val() {
return memory.ConstTrue, nil
return memory.True, nil
}
return memory.ConstFalse, nil
return memory.False, nil
case bytecode.OpOpPushStr:
var op bytecode.OpPushStr
op.Init(tab.Bytes, tab.Pos)
return v.memory.AllocBytesAddr(op.Val())
return v.memory.AllocBytesAddr(op.Val()), nil
case bytecode.OpOpPushInt:
var op bytecode.OpPushInt
op.Init(tab.Bytes, tab.Pos)
return v.memory.AllocInt64(op.Val())
return v.memory.AllocInt64(op.Val()), nil
case bytecode.OpOpPushVector:
var op bytecode.OpPushVector
op.Init(tab.Bytes, tab.Pos)
elems, err := v.stack.pop(uint32(op.Elems()))
if err != nil {
return nil, err
return memory.Nil, err
}
return v.memory.CopyVector(elems...)
return v.memory.CopyVector(elems...), nil
case bytecode.OpOpSysCall:
var op bytecode.OpSysCall
op.Init(tab.Bytes, tab.Pos)
fn := op.Name()
if fn == nil {
return nil, errEmptyDelegatorName
return memory.Nil, errEmptyDelegatorName
}
delegator, ok := v.delegators[string(fn)]
if !ok {
return nil, fmt.Errorf("delegator <%s> not exists", fn)
return memory.Nil, fmt.Errorf("delegator <%s> not exists", fn)
}
args := op.Args()
argv, err := v.stack.pop(uint32(args))
if err != nil {
return nil, err
return memory.Nil, err
}
return delegator.Delegate(&v.memory, argv)
case bytecode.OpOpRet:
return nil, errOpRet
return memory.Nil, errOpRet
default:
return nil, fmt.Errorf("unexpected frame type %s", opType)
return memory.Nil, fmt.Errorf("unexpected frame type %s", opType)
}
}
2 changes: 1 addition & 1 deletion exec/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,6 @@ func TestVM_Exec(t *testing.T) {

addr, err := exec.Exec(bcode)
require.EqualError(t, err, "failed to exec frame at 0: delegator <noname> not exists")
assert.Nil(t, addr)
assert.Equal(t, memory.Nil, addr)
})
}
Loading

0 comments on commit 296d984

Please sign in to comment.