Introduction
This file contains assembly code and object code to help you test your call
, tailcall
, and return
instructions. Because everybody’s assembly language and object code is different, you likely can’t use them directly. Instead,
Try running each
.vo
file through the disassemblersvm-dis
. If what you see looks consistent with the.vs
file, you’re probably good to go.Otherwise, try running the
.vs
file through your UFT. To get the examples to parse using your UFT, you will likely have to change some of the concrete syntax in the test cases.
Once you get the right .vo
files and all three of your instructions are working, you should be able to produce evidence like this:
> svm *.vo
The only test passed.
The only test passed.
The only test passed.
The only test passed.
The only test passed.
The only test passed.
The only test passed.
> svm *.voerr
This test should cause a checked run-time error
Run-time error (no stack trace): Callee expects 0 parameters but got 1
You can download all the tests in file tests07.zip
.
Tests for the call
instruction
For the call
instruction, I provide two passing tests and one failing test:
See if control is transferred from the caller to the callee. The callee runs
check
andexpect
, then halts, so this test doesn’t need areturn
.r0 := function (0 arguments) { r1 := "arrived" check "arrived", r1 expect "arrived", r1 halt } r0 := call r0 ()
If your assembler can’t parse that, here’s the
.vo
code:.load module 2 .load 0 function 0 4 loadliteral 1 string 7 97 114 114 105 118 101 100 check 1 string 7 97 114 114 105 118 101 100 expect 1 string 7 97 114 114 105 118 101 100 halt call 0 0 0
See if an argument can be passed and the register window works correctly. This code puts the function in register 200 and the argument in register 201. But for the test to pass, the callee must see the actual parameter in register 1. Again, the callee halts, so the test doesn’t need a
return
.r200 := function (1 arguments) { check "argument", r1 r100 := "parameter test" expect "internal literal", r100 halt } r201 := "parameter test" r0 := call r200 (r201)
If your assembler can’t parse that, here’s the
.vo
code:.load module 3 .load 200 function 1 4 check 1 string 8 97 114 103 117 109 101 110 116 loadliteral 100 string 14 112 97 114 97 109 101 116 101 114 32 116 101 115 116 expect 100 string 16 105 110 116 101 114 110 97 108 32 108 105 116 101 114 97 108 halt loadliteral 201 string 14 112 97 114 97 109 101 116 101 114 32 116 101 115 116 call 0 200 201
See if the SVM detects a function that is called with the wrong number of arguments. This test should trigger a checked run-time error.
r200 := function (0 arguments) { r100 := "If you see this message, the test fails" println r100 halt } r201 := "This test should cause a checked run-time error" println r201 r0 := call r200 (r201)
And the object code:
.load module 4 .load 200 function 0 3 loadliteral 100 string 39 73 102 32 121 111 117 32 115 101 101 32 116 104 105 115 32 109 101 115 115 97 103 101 44 32 116 104 101 32 116 101 115 116 32 102 97 105 108 115 println 100 halt loadliteral 201 string 47 84 104 105 115 32 116 101 115 116 32 115 104 111 117 108 100 32 99 97 117 115 101 32 97 32 99 104 101 99 107 101 100 32 114 117 110 45 116 105 109 101 32 101 114 114 111 114 println 201 call 0 200 201
Tests for the return
instruction
See if control is transferred to a callee and back, and if the register window is restored correctly.
goto L r0 := "This code should never have been executed" error r0 error r0 error r0 L: r100 := function (0 arguments) { r0 := r0 return r0 } r1 := "test value" check "initial assignment to r1", r1 r0 := call r100 expect "final value of r1", r1
And the object code:
.load module 10 goto 4 loadliteral 0 string 41 84 104 105 115 32 99 111 100 101 32 115 104 111 117 108 100 32 110 101 118 101 114 32 104 97 118 101 32 98 101 101 110 32 101 120 101 99 117 116 101 100 error 0 error 0 error 0 .load 100 function 0 2 move 0 0 return 0 loadliteral 1 string 10 116 101 115 116 32 118 97 108 117 101 check 1 string 24 105 110 105 116 105 97 108 32 97 115 115 105 103 110 109 101 110 116 32 116 111 32 114 49 call 0 100 100 expect 1 string 17 102 105 110 97 108 32 118 97 108 117 101 32 111 102 32 114 49
See if a value can be returned correctly.
r100 := function (0 arguments) { r1 := 1852 return r1 } r50 := call r100 check "result from calling function", r50 r200 := 1852 expect "value we expected", r200
And the object code:
.load module 5 .load 100 function 0 2 loadliteral 1 1852 return 1 call 50 100 100 check 50 string 28 114 101 115 117 108 116 32 102 114 111 109 32 99 97 108 108 105 110 103 32 102 117 110 99 116 105 111 110 loadliteral 200 1852 expect 200 string 17 118 97 108 117 101 32 119 101 32 101 120 112 101 99 116 101 100
Test recursion. Here’s a factorial test:
r0 := function (1 arguments) { ;; parameter n is in r1 r2 := 0 r2 := r1 = r2 if r2 goto L1 ;; induction step, n > 0 r2 := r0 ;; the factorial fucntion r3 := 1 r3 := r1 - r3 r2 := call r2 (r3) r2 := r1 * r2 return r2 L1: ;; base case: n == 0 r0 := 1 return r0 } global factorial := r0 r1 := 5 r0 := call r0 (r1) check "(factorial 5)", r0 r0 := 120 expect "120", r0
And the object code:
.load module 7 .load 0 function 1 12 loadliteral 2 0 = 2 1 2 if 2 goto 6 move 2 0 loadliteral 3 1 - 3 1 3 call 2 2 3 * 2 1 2 return 2 loadliteral 0 1 return 0 setglobal 0 string 9 102 97 99 116 111 114 105 97 108 loadliteral 1 5 call 0 0 1 check 0 string 13 40 102 97 99 116 111 114 105 97 108 32 53 41 loadliteral 0 120 expect 0 string 3 49 50 48
Tests for the tailcall
instruction
Test a function that run half a million iterations, then stops. (My SVM completes this test in a tenth of a second.) This one doesn’t test that registers are moved correctly: the registers used in the caller and callee are exactly the same.
;; (define big (n) (if (= n 0) n (big (- n 1)))) r0 := function (1 arguments) { ; parameter n is in r1 r2 := 0 r2 := r1 = r2 if r2 goto L1 r2 := 1 r1 := r1 - r2 tailcall r0 (r1) L1: return r1 } global big := r0 ;; (check-expect (big 555000) 0) r1 := 555000 r0 := call r0 (r1) check "(big 555000)", r0 r100 := 0 expect "0", r100
Here’s the object code:
.load module 7 .load 0 function 1 8 loadliteral 2 0 = 2 1 2 if 2 goto 3 loadliteral 2 1 - 1 1 2 tailcall 0 1 return 1 setglobal 0 string 3 98 105 103 loadliteral 1 555000 call 0 0 1 check 0 string 12 40 98 105 103 32 53 53 53 48 48 48 41 loadliteral 100 0 expect 100 string 1 48
Here’s a test that does move registers! The SVM must move all three actual parameters and
r0
. The test comes from vScheme code:(define times-plus (n m product) ; returns n * m + product (if (= n 0) product (times-plus (- n 1) m (+ m product)))) (check-expect (times-plus 1200000 12 99) 14400099)
Here’s my assembly code:
r0 := function (3 arguments) { ;; function times-plus: r1 = n, r2 = m, r3 = product r4 := 0 r4 := r1 = r4 if r4 goto L1 r4 := r0 r5 := 1 r5 := r1 - r5 r6 := r2 r7 := r2 + r3 tailcall r4 (r5, ..., r7) L1: return r3 } global times-plus := r0 r1 := 1200000 r2 := 12 r3 := 99 r0 := call r0 (r1, ..., r3) check "(times-plus 1200000 12 99)", r0 r0 := 14400099 expect "14400099", r0
And my virtual object code:
.load module 9 .load 0 function 3 11 loadliteral 4 0 = 4 1 4 if 4 goto 6 move 4 0 loadliteral 5 1 - 5 1 5 move 6 2 + 7 2 3 tailcall 4 7 return 3 setglobal 0 string 10 116 105 109 101 115 45 112 108 117 115 loadliteral 1 1200000 loadliteral 2 12 loadliteral 3 99 call 0 0 3 check 0 string 26 40 116 105 109 101 115 45 112 108 117 115 32 49 50 48 48 48 48 48 32 49 50 32 57 57 41 loadliteral 0 14400099 expect 0 string 8 49 52 52 48 48 48 57 57