diff options
Diffstat (limited to 'vm1')
| -rw-r--r-- | vm1/vm.go | 53 | ||||
| -rw-r--r-- | vm1/vm_test.go | 105 |
2 files changed, 108 insertions, 50 deletions
@@ -21,10 +21,12 @@ const ( Jump // -- ; ip += $1 JumpTrue // cond -- ; if cond { ip += $1 } Lower // n1 n2 -- cond ; cond = n1 < n2 + Loweri // n1 -- cond ; cond = n1 < $1 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. @@ -40,10 +42,12 @@ var strop = [...]string{ // for VM tracing. Jump: "Jump", JumpTrue: "JumpTrue", Lower: "Lower", + Loweri: "Loweri", Pop: "Pop", Push: "Push", Return: "Return", Sub: "Sub", + Subi: "Subi", } // Machine represents a virtual machine. @@ -61,18 +65,18 @@ func (m *Machine) Run() { defer func() { m.mem, m.ip, m.fp = mem, ip, fp }() trace := func() { - var op1 string - if len(code[ip]) > 1 { - op1 = strconv.Itoa(int(code[ip][1])) + var op2 string + if len(code[ip]) > 2 { + op2 = strconv.Itoa(int(code[ip][2])) } - fmt.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-8s %-4s] mem:%v\n", ip, sp, fp, strop[code[ip][0]], op1, mem) + fmt.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-8s %-4s] mem:%v\n", ip, sp, fp, strop[code[ip][1]], op2, mem) } _ = trace for { sp = len(mem) // stack pointer trace() - switch op := code[ip]; op[0] { // TODO: op[0] will contain file pos ? + switch op := code[ip]; op[1] { case Add: mem[sp-2] = mem[sp-2].(int) + mem[sp-1].(int) mem = mem[:sp-1] @@ -81,53 +85,58 @@ func (m *Machine) Run() { mem = mem[:sp-1] case Call: mem = append(mem, ip+1) - ip += int(op[1]) + ip += int(op[2]) continue case CallX: // Should be made optional. - in := make([]reflect.Value, int(op[1])) + l := int(op[2]) + in := make([]reflect.Value, l) for i := range in { - in[i] = reflect.ValueOf(mem[sp-1-i]) + in[l-1-i] = reflect.ValueOf(mem[sp-1-i]) } - f := reflect.ValueOf(mem[sp-len(in)-1]) - mem = mem[:sp-len(in)-1] + f := reflect.ValueOf(mem[sp-l-1]) + mem = mem[:sp-l-1] for _, v := range f.Call(in) { mem = append(mem, v.Interface()) } case Dup: - mem = append(mem, mem[int(op[1])]) + mem = append(mem, mem[int(op[2])]) case Enter: mem = append(mem, fp) fp = sp + 1 case Exit: return case Fdup: - mem = append(mem, mem[int(op[1])+fp-1]) + mem = append(mem, mem[int(op[2])+fp-1]) case Jump: - ip += int(op[1]) + ip += int(op[2]) continue case JumpTrue: cond := mem[sp-1].(bool) mem = mem[:sp-1] if cond { - ip += int(op[1]) + ip += int(op[2]) continue } case Lower: mem[sp-2] = mem[sp-2].(int) < mem[sp-1].(int) mem = mem[:sp-1] + case Loweri: + mem[sp-1] = mem[sp-1].(int) < int(op[2]) case Pop: mem = mem[:sp-1] case Push: - mem = append(mem, int(op[1])) + mem = append(mem, int(op[2])) case Return: ip = mem[fp-2].(int) ofp := fp fp = mem[fp-1].(int) - mem = append(mem[:ofp-int(op[1])-2], mem[sp-int(op[1]):]...) + mem = append(mem[:ofp-int(op[2])-2], mem[sp-int(op[2]):]...) continue case Sub: mem[sp-2] = mem[sp-2].(int) - mem[sp-1].(int) mem = mem[:sp-1] + case Subi: + mem[sp-1] = mem[sp-1].(int) - int(op[2]) } ip++ } @@ -141,3 +150,15 @@ func (m *Machine) PushCode(code [][]int64) (p int) { func (m *Machine) SetIP(ip int) { m.ip = ip } func (m *Machine) Push(v any) (l int) { l = len(m.mem); m.mem = append(m.mem, v); return } func (m *Machine) Pop() (v any) { l := len(m.mem) - 1; v = m.mem[l]; m.mem = m.mem[:l]; return } + +// Disas returns the code as a readable string. +func Disas(code [][]int64) (asm string) { + for _, op := range code { + if len(op) > 2 { + asm += fmt.Sprintf("%s %d\n", strop[op[1]], op[2]) + } else { + asm += strop[op[1]] + "\n" + } + } + return asm +} diff --git a/vm1/vm_test.go b/vm1/vm_test.go index 33ace00..1268bba 100644 --- a/vm1/vm_test.go +++ b/vm1/vm_test.go @@ -23,6 +23,21 @@ func TestVM(t *testing.T) { } } +func BenchmarkVM(b *testing.B) { + for _, test := range tests { + b.Run("", func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + m := &Machine{} + m.PushCode(test.code) + b.StartTimer() + + m.Run() + } + }) + } +} + var tests = []struct { sym []any // initial memory values code [][]int64 // bytecode to execute @@ -30,53 +45,75 @@ var tests = []struct { mem string // expected memory content }{{ // #00 -- A simple addition. code: [][]int64{ - {Push, 1}, - {Push, 2}, - {Add}, - {Exit}, + {0, Push, 1}, + {0, Push, 2}, + {0, Add}, + {0, Exit}, }, start: 0, end: 1, mem: "[3]", }, { // #01 -- Calling a function defined outside the VM. sym: []any{fmt.Println, "Hello"}, code: [][]int64{ - {CallX, 1}, - {Exit}, + {0, CallX, 1}, + {0, Exit}, }, start: 0, end: 2, mem: "[6 <nil>]", }, { // #02 -- Defining and calling a function in VM. code: [][]int64{ - {Jump, 4}, // 0 - {Enter}, // 1 - {Push, 3}, // 2 - {Return, 1}, // 3 - {Push, 1}, // 4 - {Call, -4}, // 5 - {Exit}, // 6 + {0, Jump, 4}, // 0 + {0, Enter}, // 1 + {0, Push, 3}, // 2 + {0, Return, 1}, // 3 + {0, Push, 1}, // 4 + {0, Call, -4}, // 5 + {0, Exit}, // 6 }, start: 0, end: 1, mem: "[3]", }, { // #03 -- Fibonacci numbers, hand written. Showcase recursivity. code: [][]int64{ - {Jump, 18}, // 0, goto 18 - {Enter}, // 1, - {Fdup, -2}, // 2, [i] - {Push, 2}, // 3, [i 2] - {Lower}, // 4, [true/false] - {JumpTrue, 11}, // 5, [], goto 16 - {Fdup, -2}, // 6 [i] - {Push, 2}, // 7 [i 2] - {Sub}, // 8 [(i-2)] - {Call, -8}, // 9 [fib(i-2)] - {Fdup, -2}, // 10 [fib(i-2) i] - {Push, 1}, // 11 [(i-2) i 1] - {Sub}, // 12 [(i-2) (i-1)] - {Call, -12}, // 13 [fib(i-2) fib(i-1)] - {Add}, // 14 [fib(i-2)+fib(i-1)] - {Return, 1}, // 15 return i - {Fdup, -2}, // 16 [i] - {Return, 1}, // 17 return i - {Push, 6}, // 18 [1] - {Call, -18}, // 19 [fib(*1)] - {Exit}, // 20 + {0, Jump, 18}, // 0, goto 18 + {0, Enter}, // 1, + {0, Fdup, -2}, // 2, [i] + {0, Push, 2}, // 3, [i 2] + {0, Lower}, // 4, [true/false] + {0, JumpTrue, 11}, // 5, [], goto 16 + {0, Fdup, -2}, // 6 [i] + {0, Push, 2}, // 7 [i 2] + {0, Sub}, // 8 [(i-2)] + {0, Call, -8}, // 9 [fib(i-2)] + {0, Fdup, -2}, // 10 [fib(i-2) i] + {0, Push, 1}, // 11 [(i-2) i 1] + {0, Sub}, // 12 [(i-2) (i-1)] + {0, Call, -12}, // 13 [fib(i-2) fib(i-1)] + {0, Add}, // 14 [fib(i-2)+fib(i-1)] + {0, Return, 1}, // 15 return i + {0, Fdup, -2}, // 16 [i] + {0, Return, 1}, // 17 return i + {0, Push, 6}, // 18 [1] + {0, Call, -18}, // 19 [fib(*1)] + {0, Exit}, // 20 + }, + start: 0, end: 1, mem: "[8]", +}, { // #04 -- Fibonacci with some immediate instructions. + code: [][]int64{ + {0, Jump, 15}, // 0, goto 15 + {0, Enter}, // 1, + {0, Fdup, -2}, // 2, [i] + {0, Loweri, 2}, // 3, [true/false] + {0, JumpTrue, 9}, // 4, [], goto 13 + {0, Fdup, -2}, // 5 [i] + {0, Subi, 2}, // 6 [(i-2)] + {0, Call, -6}, // 7 [fib(i-2)] + {0, Fdup, -2}, // 8 [fib(i-2) i] + {0, Subi, 1}, // 9 [(i-2) (i-1)] + {0, Call, -9}, // 10 [fib(i-2) fib(i-1)], call 1 + {0, Add}, // 11 [fib(i-2)+fib(i-1)] + {0, Return, 1}, // 12 return i + {0, Fdup, -2}, // 13 [i] + {0, Return, 1}, // 14 return i + {0, Push, 6}, // 15 [1] + {0, Call, -15}, // 16 [fib(*1)], call 1 + {0, Exit}, // 17 }, start: 0, end: 1, mem: "[8]", }} |
