* rationale? previously, the VM's stack was used for storing local variables across blocks; a Scheme procedure was split into several low-level routines (one for the procedure itself and one for each continuation), and the stack was used as a communication channel for these separate routines. in contrast, registers were local to each routine. this aligns with Wasm's model of functions pretty well, with Wasm /locals/ acting as the VM's /registers/, and a global mutable stack serving as fallback. this worked quite well until it became time to implement ~call/cc~. we are considering making the following alterations to the VM: - explicitly segment the stack into frames. - passing procedures and return addresses on the stack. * scratchpad ** Scheme source #+begin_src scheme (* 2 (call/cc (λ (cc) (begin (cc 6) 3)))) #+end_src ** CPS #+begin_src scheme (λ (ktail0) (letrec ((with-cc (λ (cc ktail1) (letrec ((k0 (κ (_) (continue ktail1 3)))) (cc 6 k0))))) (prim (call/cc with-cc) (κ (x1) (prim (* 2 x1) (κ (x2) (continue ktail0 x2))))))) #+end_src ** stack VM #+begin_src scheme ;; (call n) expects `n' values on the stack as arguments. then the ;; procedure is expected at index `n', and the return continuation ;; should be at `n+1'. (define $k0 (pop! %_) ; [ _ ret ] (push! 3) ; [ ret ] (tail-call 1) ; [ 3 ret ] ) (define $with-cc (pop! %cc) ; [ cc ret ] (push! $k0) ; [ ret ] (push! %cc) ; [ $k0 ret ] (push! 6) ; [ cc $k0 ret ] ;; call a procedure with one argument. (call 1) ; [ 6 cc $k0 ret ] ) (define $main (pop! %ktail0) ; [ ret ] (prim %x1 (call/cc $with-cc)) ; [] (prim %x2 (* 2 %x1)) ; [] (push! %ktail0) ; [] (push! %x2) ; [ ret ] (tail-call 1) ; [ %x2 ret ] ) #+end_src