diff options
| author | Marc Vertes <mvertes@free.fr> | 2025-11-14 13:47:51 +0100 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2025-11-14 13:47:51 +0100 |
| commit | 1a9c22d1219eb0239417db16c9fe96eea3ced2fe (patch) | |
| tree | a4fa82cfbbc924d281a94e307656a7af14caadcd /vm | |
| parent | a4d7730581e8e65faa6a9285d107a041accf60b1 (diff) | |
fix: refactor VM instruction type
Use custom types for VM instructions. More idiomatic code for tracing.
Diffstat (limited to 'vm')
| -rw-r--r-- | vm/op_string.go | 57 | ||||
| -rw-r--r-- | vm/vm.go | 243 | ||||
| -rw-r--r-- | vm/vm_test.go | 264 |
3 files changed, 281 insertions, 283 deletions
diff --git a/vm/op_string.go b/vm/op_string.go new file mode 100644 index 0000000..ef3f3ee --- /dev/null +++ b/vm/op_string.go @@ -0,0 +1,57 @@ +// Code generated by "stringer -type=Op"; DO NOT EDIT. + +package vm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Nop-0] + _ = x[Add-1] + _ = x[Addr-2] + _ = x[Assign-3] + _ = x[Fassign-4] + _ = x[Vassign-5] + _ = x[Call-6] + _ = x[Calli-7] + _ = x[CallX-8] + _ = x[Deref-9] + _ = x[Dup-10] + _ = x[Fdup-11] + _ = x[Equal-12] + _ = x[EqualSet-13] + _ = x[Exit-14] + _ = x[Field-15] + _ = x[Greater-16] + _ = x[Grow-17] + _ = x[Index-18] + _ = x[Jump-19] + _ = x[JumpTrue-20] + _ = x[JumpFalse-21] + _ = x[JumpSetTrue-22] + _ = x[JumpSetFalse-23] + _ = x[Lower-24] + _ = x[Loweri-25] + _ = x[Mul-26] + _ = x[New-27] + _ = x[Not-28] + _ = x[Pop-29] + _ = x[Push-30] + _ = x[Return-31] + _ = x[Sub-32] + _ = x[Subi-33] +} + +const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupEqualEqualSetExitFieldGreaterGrowIndexJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNotPopPushReturnSubSubi" + +var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 61, 69, 73, 78, 85, 89, 94, 98, 106, 115, 126, 138, 143, 149, 152, 155, 158, 161, 165, 171, 174, 178} + +func (i Op) String() string { + idx := int(i) - 0 + if i < 0 || idx >= len(_Op_index)-1 { + return "Op(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Op_name[_Op_index[idx]:_Op_index[idx+1]] +} @@ -5,126 +5,98 @@ import ( "fmt" // for tracing only "log" // for tracing only "reflect" // for optional CallX only - "strconv" // for tracing only "unsafe" // to allow setting unexported struct fields ) const debug = true +type ( + Op int // Op is a VM opcode (bytecode instruction). + Pos int // Pos is the source code position of instruction +) + +//go:generate stringer -type=Op + // Byte-code instruction set. const ( // Instruction effect on stack: values consumed -- values produced. - Nop = iota // -- - Add // n1 n2 -- sum ; sum = n1+n2 - Addr // a -- &a ; - Assign // val -- ; mem[$1] = val - Fassign // val -- ; mem[$1] = val - Vassign // val dest -- ; dest.Set(val) - Call // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...) - Calli // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...) - CallX // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = mem[f](a1, ...) - Deref // x -- *x ; - Dup // addr -- value ; value = mem[addr] - Fdup // addr -- value ; value = mem[addr] - Equal // n1 n2 -- cond ; cond = n1 == n2 - EqualSet // n1 n2 -- n1 cond ; cond = n1 == n2 - Exit // -- ; - Field // s -- f ; f = s.FieldIndex($1, ...) - Greater // n1 n2 -- cond; cond = n1 > n2 - Grow // -- ; sp += $1 - Index // a i -- a[i] ; - Jump // -- ; ip += $1 - JumpTrue // cond -- ; if cond { ip += $1 } - JumpFalse // cond -- ; if cond { ip += $1 } - JumpSetTrue // - JumpSetFalse // - Lower // n1 n2 -- cond ; cond = n1 < n2 - Loweri // n1 -- cond ; cond = n1 < $1 - Mul // n1 n2 -- prod ; prod = n1*n2 - New // -- x; mem[fp+$1] = new mem[$2] - Not // c -- r ; r = !c - Pop // v -- - Push // -- v - Return // [r1 .. ri] -- ; exit frame: sp = fp, fp = pop - Sub // n1 n2 -- diff ; diff = n1 - n2 - Subi // n1 -- diff ; diff = n1 - $1 + Nop Op = iota // -- + Add // n1 n2 -- sum ; sum = n1+n2 + Addr // a -- &a ; + Assign // val -- ; mem[$1] = val + Fassign // val -- ; mem[$1] = val + Vassign // val dest -- ; dest.Set(val) + Call // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...) + Calli // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...) + CallX // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = mem[f](a1, ...) + Deref // x -- *x ; + Dup // addr -- value ; value = mem[addr] + Fdup // addr -- value ; value = mem[addr] + Equal // n1 n2 -- cond ; cond = n1 == n2 + EqualSet // n1 n2 -- n1 cond ; cond = n1 == n2 + Exit // -- ; + Field // s -- f ; f = s.FieldIndex($1, ...) + Greater // n1 n2 -- cond; cond = n1 > n2 + Grow // -- ; sp += $1 + Index // a i -- a[i] ; + Jump // -- ; ip += $1 + JumpTrue // cond -- ; if cond { ip += $1 } + JumpFalse // cond -- ; if cond { ip += $1 } + JumpSetTrue // + JumpSetFalse // + Lower // n1 n2 -- cond ; cond = n1 < n2 + Loweri // n1 -- cond ; cond = n1 < $1 + Mul // n1 n2 -- prod ; prod = n1*n2 + New // -- x; mem[fp+$1] = new mem[$2] + Not // c -- r ; r = !c + Pop // v -- + Push // -- v + Return // [r1 .. ri] -- ; exit frame: sp = fp, fp = pop + Sub // n1 n2 -- diff ; diff = n1 - n2 + Subi // n1 -- diff ; diff = n1 - $1 ) -var strop = [...]string{ // for VM tracing. - Nop: "Nop", - Add: "Add", - Addr: "Addr", - Assign: "Assign", - Call: "Call", - Calli: "Calli", - CallX: "CallX", - Deref: "Deref", - Dup: "Dup", - Equal: "Equal", - EqualSet: "EqualSet", - Exit: "Exit", - Fassign: "Fassign", - Fdup: "Fdup", - Field: "Field", - Greater: "Greater", - Grow: "Grow", - Index: "Index", - Jump: "Jump", - JumpTrue: "JumpTrue", - JumpFalse: "JumpFalse", - JumpSetTrue: "JumpSetTrue", - JumpSetFalse: "JumpSetFalse", - Lower: "Lower", - Loweri: "Loweri", - Mul: "Mul", - New: "New", - Not: "Not", - Pop: "Pop", - Push: "Push", - Return: "Return", - Sub: "Sub", - Subi: "Subi", - Vassign: "Vassign", +// Instruction represents a virtual machine bytecode instruction. +type Instruction struct { + Pos // position in source + Op // opcode + Arg []int // arguments +} + +func (i Instruction) String() (s string) { + s = i.Op.String() + for _, a := range i.Arg { + s += fmt.Sprintf(" %v", a) + } + return s } // Code represents the virtual machine byte code. -type Code [][]int64 +type Code []Instruction // Machine represents a virtual machine. type Machine struct { code Code // code to execute mem []Value // memory, as a stack - ip, fp int // instruction and frame pointer + ip, fp int // instruction pointer and frame pointer ic uint64 // instruction counter, incremented at each instruction executed // flags uint // to set options such as restrict CallX, etc... } // Run runs a program. func (m *Machine) Run() (err error) { - code, mem, ip, fp, sp, ic := m.code, m.mem, m.ip, m.fp, 0, m.ic + mem, ip, fp, sp, ic := m.mem, m.ip, m.fp, 0, m.ic defer func() { m.mem, m.ip, m.fp, m.ic = mem, ip, fp, ic }() - trace := func() { - if !debug { - return - } - var op2, op3 string - c := code[ip] - if l := len(c); l > 2 { - op2 = strconv.Itoa(int(c[2])) - if l > 3 { - op3 = strconv.Itoa(int(c[3])) - } - } - log.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-12s %-4s %-4s] mem:%v\n", ip, sp, fp, strop[c[1]], op2, op3, Vstring(mem)) - } - for { sp = len(mem) // stack pointer - trace() + c := m.code[ip] + if debug { + log.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-14v] mem:%v\n", ip, sp, fp, c, Vstring(mem)) + } ic++ - switch op := code[ip]; op[1] { + switch c.Op { case Add: mem[sp-2] = ValueOf(int(mem[sp-2].Data.Int() + mem[sp-1].Data.Int())) mem = mem[:sp-1] @@ -134,10 +106,10 @@ func (m *Machine) Run() (err error) { case Addr: mem[sp-1].Data = mem[sp-1].Data.Addr() case Assign: - mem[op[2]].Data.Set(mem[sp-1].Data) + mem[c.Arg[0]].Data.Set(mem[sp-1].Data) mem = mem[:sp-1] case Fassign: - mem[fp+int(op[2])-1].Data.Set(mem[sp-1].Data) + mem[fp+c.Arg[0]-1].Data.Set(mem[sp-1].Data) mem = mem[:sp-1] case Call: nip := int(mem[sp-1].Data.Int()) @@ -148,25 +120,24 @@ func (m *Machine) Run() (err error) { case Calli: mem = append(mem, ValueOf(ip+1), ValueOf(fp)) fp = sp + 2 - ip = int(op[2]) + ip = c.Arg[0] continue case CallX: // Should be made optional. - l := int(op[2]) - in := make([]reflect.Value, l) + in := make([]reflect.Value, c.Arg[0]) for i := range in { in[i] = mem[sp-2-i].Data } f := mem[sp-1].Data - mem = mem[:sp-l-1] + mem = mem[:sp-c.Arg[0]-1] for _, v := range f.Call(in) { mem = append(mem, Value{Data: v}) } case Deref: mem[sp-1].Data = mem[sp-1].Data.Elem() case Dup: - mem = append(mem, mem[int(op[2])]) + mem = append(mem, mem[c.Arg[0]]) case New: - mem[int(op[2])+fp-1] = NewValue(mem[int(op[3])].Type) + mem[c.Arg[0]+fp-1] = NewValue(mem[c.Arg[1]].Type) case Equal: mem[sp-2] = ValueOf(mem[sp-2].Data.Equal(mem[sp-1].Data)) mem = mem[:sp-1] @@ -183,44 +154,44 @@ func (m *Machine) Run() (err error) { case Exit: return err case Fdup: - mem = append(mem, mem[int(op[2])+fp-1]) + mem = append(mem, mem[c.Arg[0]+fp-1]) case Field: - fv := mem[sp-1].Data.FieldByIndex(slint(op[2:])) + fv := mem[sp-1].Data.FieldByIndex(c.Arg) if !fv.CanSet() { // Normally private fields can not bet set via reflect. Override this limitation. fv = reflect.NewAt(fv.Type(), unsafe.Pointer(fv.UnsafeAddr())).Elem() } mem[sp-1].Data = fv case Jump: - ip += int(op[2]) + ip += c.Arg[0] continue case JumpTrue: cond := mem[sp-1].Data.Bool() mem = mem[:sp-1] if cond { - ip += int(op[2]) + ip += c.Arg[0] continue } case JumpFalse: cond := mem[sp-1].Data.Bool() mem = mem[:sp-1] if !cond { - ip += int(op[2]) + ip += c.Arg[0] continue } case JumpSetTrue: cond := mem[sp-1].Data.Bool() if cond { - ip += int(op[2]) - // Note that stack is not modified if cond is true + ip += c.Arg[0] + // Note that the stack is not modified if cond is true. continue } mem = mem[:sp-1] case JumpSetFalse: cond := mem[sp-1].Data.Bool() if !cond { - ip += int(op[2]) - // Note that stack is not modified if cond is false + ip += c.Arg[0] + // Note that the stack is not modified if cond is false. continue } mem = mem[:sp-1] @@ -231,28 +202,27 @@ func (m *Machine) Run() (err error) { mem[sp-2] = ValueOf(mem[sp-1].Data.Int() < mem[sp-2].Data.Int()) mem = mem[:sp-1] case Loweri: - mem[sp-1] = ValueOf(mem[sp-1].Data.Int() < op[2]) + mem[sp-1] = ValueOf(mem[sp-1].Data.Int() < int64(c.Arg[0])) case Not: mem[sp-1] = ValueOf(!mem[sp-1].Data.Bool()) case Pop: - mem = mem[:sp-int(op[2])] + mem = mem[:sp-c.Arg[0]] case Push: - // mem = append(mem, reflect.ValueOf(int(op[2]))) mem = append(mem, NewValue(TypeOf(0))) - mem[sp].Data.SetInt(op[2]) + mem[sp].Data.SetInt(int64(c.Arg[0])) case Grow: - mem = append(mem, make([]Value, op[2])...) + mem = append(mem, make([]Value, c.Arg[0])...) case Return: ip = int(mem[fp-2].Data.Int()) ofp := fp fp = int(mem[fp-1].Data.Int()) - mem = append(mem[:ofp-int(op[2])-int(op[3])-1], mem[sp-int(op[2]):]...) + mem = append(mem[:ofp-c.Arg[0]-c.Arg[1]-1], mem[sp-c.Arg[0]:]...) continue case Sub: mem[sp-2] = ValueOf(int(mem[sp-1].Data.Int() - mem[sp-2].Data.Int())) mem = mem[:sp-1] case Subi: - mem[sp-1] = ValueOf(int(mem[sp-1].Data.Int() - op[2])) + mem[sp-1] = ValueOf(int(mem[sp-1].Data.Int()) - c.Arg[0]) case Index: mem[sp-2].Data = mem[sp-1].Data.Index(int(mem[sp-2].Data.Int())) mem = mem[:sp-1] @@ -265,7 +235,7 @@ func (m *Machine) Run() (err error) { } // PushCode adds instructions to the machine code. -func (m *Machine) PushCode(code ...[]int64) (p int) { +func (m *Machine) PushCode(code ...Instruction) (p int) { p = len(m.code) m.code = append(m.code, code...) return p @@ -282,12 +252,12 @@ func (m *Machine) Push(v ...Value) (l int) { } // Pop removes and returns the value on the top of machine stack. -func (m *Machine) Pop() (v Value) { - l := len(m.mem) - 1 - v = m.mem[l] - m.mem = m.mem[:l] - return v -} +// func (m *Machine) Pop() (v Value) { +// l := len(m.mem) - 1 +// v = m.mem[l] +// m.mem = m.mem[:l] +// return v +// } // Top returns (but not remove) the value on the top of machine stack. func (m *Machine) Top() (v Value) { @@ -299,40 +269,11 @@ func (m *Machine) Top() (v Value) { // PopExit removes the last machine code instruction if is Exit. func (m *Machine) PopExit() { - if l := len(m.code); l > 0 && m.code[l-1][1] == Exit { + if l := len(m.code); l > 0 && m.code[l-1].Op == Exit { m.code = m.code[:l-1] } } -// CodeString returns the string representation of a machine code instruction. -func CodeString(op []int64) string { - switch len(op) { - case 2: - return strop[op[1]] - case 3: - return fmt.Sprintf("%s %d", strop[op[1]], op[2]) - case 4: - return fmt.Sprintf("%s %d %d", strop[op[1]], op[2], op[3]) - } - return "" -} - -// Disassemble returns the code as a readable string. -func Disassemble(code [][]int64) (asm string) { - for _, op := range code { - asm += CodeString(op) + "\n" - } - return asm -} - -func slint(a []int64) []int { - r := make([]int, len(a)) - for i, v := range a { - r[i] = int(v) - } - return r -} - // Vstring returns the string repreentation of a list of values. func Vstring(lv []Value) string { s := "[" diff --git a/vm/vm_test.go b/vm/vm_test.go index 43333ad..f7cbfbf 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -50,189 +50,189 @@ func BenchmarkVM(b *testing.B) { } var tests = []struct { - sym []Value // initial memory values - code [][]int64 // bytecode to execute - start, end int // - mem string // expected memory content + sym []Value // initial memory values + code []Instruction // bytecode to execute + start, end int // + mem string // expected memory content }{{ // #00 -- A simple addition. - code: [][]int64{ - {0, Push, 1}, - {0, Push, 2}, - {0, Add}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{1}}, + {Op: Push, Arg: []int{2}}, + {Op: Add}, + {Op: Exit}, }, start: 0, end: 1, mem: "[3]", }, { // #01 -- A simple subtraction. - code: [][]int64{ - {0, Push, 2}, - {0, Push, 3}, - {0, Sub}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{2}}, + {Op: Push, Arg: []int{3}}, + {Op: Sub}, + {Op: Exit}, }, start: 0, end: 1, mem: "[1]", }, { // #02 -- A simple multiplication. - code: [][]int64{ - {0, Push, 3}, - {0, Push, 2}, - {0, Mul}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{3}}, + {Op: Push, Arg: []int{2}}, + {Op: Mul}, + {Op: Exit}, }, start: 0, end: 1, mem: "[6]", }, { // #03 -- lower. - code: [][]int64{ - {0, Push, 3}, - {0, Push, 2}, - {0, Lower}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{3}}, + {Op: Push, Arg: []int{2}}, + {Op: Lower}, + {Op: Exit}, }, start: 0, end: 1, mem: "[true]", }, { // #04 -- greater. - code: [][]int64{ - {0, Push, 2}, - {0, Push, 3}, - {0, Greater}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{2}}, + {Op: Push, Arg: []int{3}}, + {Op: Greater}, + {Op: Exit}, }, start: 0, end: 1, mem: "[true]", }, { // #05 -- equal. - code: [][]int64{ - {0, Push, 2}, - {0, Push, 3}, - {0, Equal}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{2}}, + {Op: Push, Arg: []int{3}}, + {Op: Equal}, + {Op: Exit}, }, start: 0, end: 1, mem: "[false]", }, { // #06 -- equalSet. - code: [][]int64{ - {0, Push, 2}, - {0, Push, 3}, - {0, EqualSet}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{2}}, + {Op: Push, Arg: []int{3}}, + {Op: EqualSet}, + {Op: Exit}, }, start: 0, end: 2, mem: "[2 false]", }, { // #07 -- equalSet. - code: [][]int64{ - {0, Push, 3}, - {0, Push, 3}, - {0, EqualSet}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{3}}, + {Op: Push, Arg: []int{3}}, + {Op: EqualSet}, + {Op: Exit}, }, start: 0, end: 1, mem: "[true]", }, { // #08 not. - code: [][]int64{ - {0, Push, 3}, - {0, Push, 3}, - {0, Equal}, - {0, Not}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{3}}, + {Op: Push, Arg: []int{3}}, + {Op: Equal}, + {Op: Not}, + {Op: Exit}, }, start: 0, end: 1, mem: "[false]", }, { // #09 pop. - code: [][]int64{ - {0, Push, 3}, - {0, Push, 2}, - {0, Pop, 1}, - {0, Exit}, + code: []Instruction{ + {Op: Push, Arg: []int{3}}, + {Op: Push, Arg: []int{2}}, + {Op: Pop, Arg: []int{1}}, + {Op: Exit}, }, start: 0, end: 1, mem: "[3]", }, { // #10 -- Assign a variable. sym: []Value{{Type: TypeOf(0), Data: reflect.ValueOf(0)}}, - code: [][]int64{ - {0, Grow, 1}, - {0, New, 2, 0}, - {0, Push, 2}, - {0, Assign, 1}, - {0, Exit}, + code: []Instruction{ + {Op: Grow, Arg: []int{1}}, + {Op: New, Arg: []int{2, 0}}, + {Op: Push, Arg: []int{2}}, + {Op: Assign, Arg: []int{1}}, + {Op: Exit}, }, start: 1, end: 2, mem: "[2]", }, { // #11 -- Calling a function defined outside the VM. sym: []Value{ValueOf(fmt.Println), ValueOf("Hello")}, - code: [][]int64{ - {0, Dup, 0}, - {0, CallX, 1}, - {0, Exit}, + code: []Instruction{ + {Op: Dup, Arg: []int{0}}, + {Op: CallX, Arg: []int{1}}, + {Op: Exit}, }, start: 1, end: 3, mem: "[6 <nil>]", }, { // #12 -- Defining and calling a function in VM. - code: [][]int64{ - {0, Jump, 3}, // 0 - {0, Push, 3}, // 1 - {0, Return, 1, 1}, // 2 - {0, Push, 1}, // 3 - {0, Calli, 1}, // 4 - {0, Exit}, // 5 + code: []Instruction{ + {Op: Jump, Arg: []int{3}}, // 0 + {Op: Push, Arg: []int{3}}, // 1 + {Op: Return, Arg: []int{1, 1}}, // 2 + {Op: Push, Arg: []int{1}}, // 3 + {Op: Calli, Arg: []int{1}}, // 4 + {Op: Exit}, // 5 }, start: 0, end: 1, mem: "[3]", }, { // #13 -- Defining and calling a function in VM. - code: [][]int64{ - {0, Jump, 3}, // 0 - {0, Push, 3}, // 1 - {0, Return, 1, 1}, // 2 - {0, Push, 1}, // 3 - {0, Push, 1}, // 4 - {0, Call}, // 5 - {0, Exit}, // 6 + code: []Instruction{ + {Op: Jump, Arg: []int{3}}, // 0 + {Op: Push, Arg: []int{3}}, // 1 + {Op: Return, Arg: []int{1, 1}}, // 2 + {Op: Push, Arg: []int{1}}, // 3 + {Op: Push, Arg: []int{1}}, // 4 + {Op: Call}, // 5 + {Op: Exit}, // 6 }, start: 0, end: 1, mem: "[3]", }, { // #14 -- Defining and calling a function in VM. - code: [][]int64{ - {0, Jump, 5}, // 0 - {0, Push, 3}, // 1 - {0, Fassign, -2}, // 2 - {0, Fdup, -2}, // 3 - {0, Return, 1, 1}, // 4 - {0, Push, 1}, // 5 - {0, Push, 1}, // 6 - {0, Call}, // 7 - {0, Exit}, // 8 + code: []Instruction{ + {Op: Jump, Arg: []int{5}}, // 0 + {Op: Push, Arg: []int{3}}, // 1 + {Op: Fassign, Arg: []int{-2}}, // 2 + {Op: Fdup, Arg: []int{-2}}, // 3 + {Op: Return, Arg: []int{1, 1}}, // 4 + {Op: Push, Arg: []int{1}}, // 5 + {Op: Push, Arg: []int{1}}, // 6 + {Op: Call}, // 7 + {Op: Exit}, // 8 }, start: 0, end: 1, mem: "[3]", }, { // #15 -- Fibonacci numbers, hand written. Showcase recursivity. - code: [][]int64{ - {0, Jump, 19}, // 0 - {0, Push, 2}, // 2 [2] - {0, Fdup, -2}, // 1 [2 i] - {0, Lower}, // 3 [true/false] - {0, JumpTrue, 13}, // 4 [], goto 17 - {0, Push, 2}, // 5 [i 2] - {0, Fdup, -2}, // 6 [i] - {0, Sub}, // 7 [(i-2)] - {0, Push, 1}, // 8 - {0, Call}, // 9 [fib(i-2)] - {0, Push, 1}, // 10 [(i-2) i 1] - {0, Fdup, -2}, // 11 [fib(i-2) i] - {0, Sub}, // 12 [(i-2) (i-1)] - {0, Push, 1}, // 13 - {0, Call}, // 14 [fib(i-2) fib(i-1)] - {0, Add}, // 15 [fib(i-2)+fib(i-1)] - {0, Return, 1, 1}, // 16 return i - {0, Fdup, -2}, // 17 [i] - {0, Return, 1, 1}, // 18 return i - {0, Push, 6}, // 19 [1] - {0, Push, 1}, // 20 - {0, Call}, // 21 [fib(*1)] - {0, Exit}, // 22 + code: []Instruction{ + {Op: Jump, Arg: []int{19}}, // 0 + {Op: Push, Arg: []int{2}}, // 2 [2] + {Op: Fdup, Arg: []int{-2}}, // 1 [2 i] + {Op: Lower}, // 3 [true/false] + {Op: JumpTrue, Arg: []int{13}}, // 4 [], goto 17 + {Op: Push, Arg: []int{2}}, // 5 [i 2] + {Op: Fdup, Arg: []int{-2}}, // 6 [i] + {Op: Sub}, // 7 [(i-2)] + {Op: Push, Arg: []int{1}}, // 8 + {Op: Call}, // 9 [fib(i-2)] + {Op: Push, Arg: []int{1}}, // 10 [(i-2) i 1] + {Op: Fdup, Arg: []int{-2}}, // 11 [fib(i-2) i] + {Op: Sub}, // 12 [(i-2) (i-1)] + {Op: Push, Arg: []int{1}}, // 13 + {Op: Call}, // 14 [fib(i-2) fib(i-1)] + {Op: Add}, // 15 [fib(i-2)+fib(i-1)] + {Op: Return, Arg: []int{1, 1}}, // 16 return i + {Op: Fdup, Arg: []int{-2}}, // 17 [i] + {Op: Return, Arg: []int{1, 1}}, // 18 return i + {Op: Push, Arg: []int{6}}, // 19 [1] + {Op: Push, Arg: []int{1}}, // 20 + {Op: Call}, // 21 [fib(*1)] + {Op: Exit}, // 22 }, start: 0, end: 1, mem: "[8]", }, { // #16 -- Fibonacci with some immediate instructions. - code: [][]int64{ - {0, Jump, 14}, // 0 - {0, Fdup, -2}, // 1 [i] - {0, Loweri, 2}, // 2 [true/false] - {0, JumpTrue, 9}, // 3 [], goto 12 - {0, Fdup, -2}, // 4 [i] - {0, Subi, 2}, // 5 [(i-2)] - {0, Calli, 1}, // 6 [fib(i-2)] - {0, Fdup, -2}, // 7 [fib(i-2) i] - {0, Subi, 1}, // 8 [(i-2) (i-1)] - {0, Calli, 1}, // 9 [fib(i-2) fib(i-1)], call 1 - {0, Add}, // 10 [fib(i-2)+fib(i-1)] - {0, Return, 1, 1}, // 11 return i - {0, Fdup, -2}, // 12 [i] - {0, Return, 1, 1}, // 13 return i - {0, Push, 6}, // 14 [1] - {0, Calli, 1}, // 15 [fib(*1)], call 1 - {0, Exit}, // 16 + code: []Instruction{ + {Op: Jump, Arg: []int{14}}, // 0 + {Op: Fdup, Arg: []int{-2}}, // 1 [i] + {Op: Loweri, Arg: []int{2}}, // 2 [true/false] + {Op: JumpTrue, Arg: []int{9}}, // 3 [], goto 12 + {Op: Fdup, Arg: []int{-2}}, // 4 [i] + {Op: Subi, Arg: []int{2}}, // 5 [(i-2)] + {Op: Calli, Arg: []int{1}}, // 6 [fib(i-2)] + {Op: Fdup, Arg: []int{-2}}, // 7 [fib(i-2) i] + {Op: Subi, Arg: []int{1}}, // 8 [(i-2) (i-1)] + {Op: Calli, Arg: []int{1}}, // 9 [fib(i-2) fib(i-1)], call 1 + {Op: Add}, // 10 [fib(i-2)+fib(i-1)] + {Op: Return, Arg: []int{1, 1}}, // 11 return i + {Op: Fdup, Arg: []int{-2}}, // 12 [i] + {Op: Return, Arg: []int{1, 1}}, // 13 return i + {Op: Push, Arg: []int{6}}, // 14 [1] + {Op: Calli, Arg: []int{1}}, // 15 [fib(*1)], call 1 + {Op: Exit}, // 16 }, start: 0, end: 1, mem: "[8]", }} |
