Skip to content

Commit

Permalink
Feat: add instruction limit in run program
Browse files Browse the repository at this point in the history
  • Loading branch information
cloverstd authored and lujjjh committed May 25, 2019
1 parent 14d9f1a commit 53750ea
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 1 deletion.
4 changes: 4 additions & 0 deletions program.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ func (p *Program) defineLit(v Value) uint {
p.values = append(p.values, v)
return index
}

func (p *Program) InstructionNumber() int {
return len(p.code)
}
4 changes: 4 additions & 0 deletions runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ func (r *Runtime) Global() *Global {
return r.global
}

func (r *Runtime) SetCyclesLimit(max int) {
r.vm.cyclesLimit = max
}

func (r *Runtime) RunProgram(ctx context.Context, program *Program) (Value, error) {
r.vm.program = program
r.vm.pc = 0
Expand Down
29 changes: 29 additions & 0 deletions runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,35 @@ func TestRunExamples(t *testing.T) {
}
}

func TestExceedInstructionLimit(t *testing.T) {
src := `
(function (x) {
return function (f) {
return function () {
return f(x(x)(f))();
};
};
})(function (x) {
return function (f) {
return function () {
return f(x(x)(f))();
};
};
})(function (f) {
return function () {
return f();
};
})()
`

r := New()
r.SetCyclesLimit(5)
_, err := r.RunString(src)
if err != ErrCyclesLimitExceeded {
t.Errorf("cycles limit exceeded expected")
}
}

func BenchmarkRunProgram(b *testing.B) {
program, err := Compile(`"hello"[0] + 1 && false`)
if err != nil {
Expand Down
14 changes: 13 additions & 1 deletion vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ type ctx struct {
pc, bp int
}

var ErrStackOverflow = errors.New("stack overflow")
var (
ErrStackOverflow = errors.New("stack overflow")
ErrCyclesLimitExceeded = errors.New("cycles limit exceeded")
)

func (v *valueStack) init() {
v.l = v.l[:0]
Expand Down Expand Up @@ -106,6 +109,8 @@ type vm struct {
callStack []ctx
bp int
program *Program

cyclesLimit int
}

func (vm *vm) newStash() {
Expand Down Expand Up @@ -136,11 +141,18 @@ func (vm *vm) run() (err error) {

vm.halt = false
ctx := vm.ctx
remainingCycles := vm.cyclesLimit

for !vm.halt {
select {
case <-ctx.Done():
return ctx.Err()
default:
if remainingCycles > 0 {
if remainingCycles--; remainingCycles == 0 {
return ErrCyclesLimitExceeded
}
}
}
vm.program.code[vm.pc].exec(vm)
}
Expand Down

0 comments on commit 53750ea

Please sign in to comment.