go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit a3073f6189b34da5d4e8bc71cb7f1b3882dde154
parent 6325ef4afda403c1b4db5f6d6ee3f13e8813078a
Author: lash <dev@holbrook.no>
Date:   Thu,  6 Apr 2023 10:08:40 +0100

WIP Add termination handler in engine

Diffstat:
Mgo/asm/asm.go | 1-
Mgo/dev/interactive.go | 3++-
Mgo/engine/engine.go | 26+++++++++++++++++++++-----
Mgo/engine/engine_test.go | 2+-
Mgo/state/state.go | 20++++++++++++++++++++
Mgo/vm/runner.go | 6+++---
Mgo/vm/vm.go | 17-----------------
7 files changed, 47 insertions(+), 28 deletions(-)

diff --git a/go/asm/asm.go b/go/asm/asm.go @@ -321,7 +321,6 @@ func(bt *Batcher) MenuExit(w io.Writer) (int, error) { } bt.inMenu = false b := bt.menuProcessor.ToLines() - log.Printf("tolines %v", b) return w.Write(b) } diff --git a/go/dev/interactive.go b/go/dev/interactive.go @@ -41,7 +41,7 @@ func main() { os.Exit(1) } in = strings.TrimSpace(in) - err = en.Exec([]byte(in), ctx) + running, err = en.Exec([]byte(in), ctx) if err != nil { fmt.Fprintf(os.Stderr, "execution terminated: %v\n", err) os.Exit(1) @@ -50,4 +50,5 @@ func main() { en.WriteResult(b) fmt.Println(b.String()) } + } diff --git a/go/engine/engine.go b/go/engine/engine.go @@ -59,22 +59,38 @@ func(en *Engine) Init(sym string, ctx context.Context) error { // - input is objectively invalid (too long etc) // - no current bytecode is available // - input processing against bytcode failed -func (en *Engine) Exec(input []byte, ctx context.Context) error { +func (en *Engine) Exec(input []byte, ctx context.Context) (bool, error) { err := en.st.SetInput(input) if err != nil { - return err + return false, err } log.Printf("new execution with input '%s' (0x%x)", input, input) code, err := en.st.GetCode() if err != nil { - return err + return false, err } if len(code) == 0 { - return fmt.Errorf("no code to execute") + return false, fmt.Errorf("no code to execute") } code, err = vm.Run(code, en.st, en.rs, ctx) + if err != nil { + return false, err + } + + v, err := en.st.MatchFlag(state.FLAG_TERMINATE, false) + if err != nil { + return false, err + } + if v { + if len(code) > 0 { + log.Printf("terminated with code remaining: %x", code) + } + return false, nil + } + en.st.SetCode(code) - return err + + return true, nil } // WriteResult writes the output of the last vm execution to the given writer. diff --git a/go/engine/engine_test.go b/go/engine/engine_test.go @@ -97,7 +97,7 @@ func TestEngineInit(t *testing.T) { } input := []byte("1") - err = en.Exec(input, ctx) + _, err = en.Exec(input, ctx) if err != nil { t.Fatal(err) } diff --git a/go/state/state.go b/go/state/state.go @@ -135,6 +135,26 @@ func(st *State) FlagByteSize() uint8 { return uint8(len(st.Flags)) } +// MatchFlag matches the current state of the given flag. +// +// The flag is specified given its bit index in the bit field. +// +// If invertMatch is set, a positive result will be returned if the flag is not set. +func(st *State) MatchFlag(sig uint32, invertMatch bool) (bool, error) { + r, err := st.GetFlag(sig) + if err != nil { + return false, err + } + if invertMatch { + if !r { + return true, nil + } + } else if r { + return true, nil + } + return false, nil +} + // GetIndex scans a byte slice in same order as in storage, and returns the index of the first set bit. // // If the given byte slice is too small for the bit field bitsize, the check will terminate at end-of-data without error. diff --git a/go/vm/runner.go b/go/vm/runner.go @@ -82,7 +82,7 @@ func RunDeadCheck(b []byte, st *state.State, rs resource.Resource, ctx context.C return b, nil } log.Printf("no code remaining, let's check if we terminate") - r, err := matchFlag(st, state.FLAG_TERMINATE, false) + r, err := st.MatchFlag(state.FLAG_TERMINATE, false) if err != nil { panic(err) } @@ -114,7 +114,7 @@ func RunCatch(b []byte, st *state.State, rs resource.Resource, ctx context.Conte if err != nil { return b, err } - r, err := matchFlag(st, sig, mode) + r, err := st.MatchFlag(sig, mode) if err != nil { return b, err } @@ -132,7 +132,7 @@ func RunCroak(b []byte, st *state.State, rs resource.Resource, ctx context.Conte if err != nil { return b, err } - r, err := matchFlag(st, sig, mode) + r, err := st.MatchFlag(sig, mode) if err != nil { return b, err } diff --git a/go/vm/vm.go b/go/vm/vm.go @@ -3,8 +3,6 @@ package vm import ( "encoding/binary" "fmt" - - "git.defalsify.org/festive/state" ) // NewLine creates a new instruction line for the VM. @@ -177,21 +175,6 @@ func parseSig(b []byte) (uint32, bool, []byte, error) { return sig, matchmode, b, nil } -// TODO: move to state -func matchFlag(st *state.State, sig uint32, invertMatch bool) (bool, error) { - r, err := st.GetFlag(sig) - if err != nil { - return false, err - } - if invertMatch { - if !r { - return true, nil - } - } else if r { - return true, nil - } - return false, nil -} // split bytecode into head and b using length-prefixed bitfield func byteSplit(b []byte) ([]byte, []byte, error) {