Scm_VMCallCC (5)

ええと、件の手続きですが作文不能な状態みたいなのでポイント列挙でとりあえず。

  • save_cont 手続きにて、コメントによれば_継続フレームを heap にコピーとある
    • 詳細は未だ不明
  • ScmEscapePoint 型のオブジェクト生成して属性に vm のナニをセット
    • 基本的には全部ポインタ? (handlers 属性は微妙
    • よく考えたら vm->cont とか呼び出し時点の継続だな
      • 最初は呼び出された継続? って思ってた
      • あら? なんか違うかも
      • そうか。call/cc 呼ばれた時点で継続を保管しておかないと駄目だな
  • 補足した継続を呼び出した時、実際に呼び出されるのは throw_continuation
    • 呼び出し時 (SCM_VM_CALL) にて ep が格納されてる data 属性が throw_continuation に渡される
    • throw_continuation のいっちゃんケツで呼ばれる throw_cont_body がナニ
    • 細かい事は抜きにして
      • vm->pc に RET
      • vm->cont に ep->cont (??
    • で、引数戻して処理終了
    • 継続が pop されて、って ScmContFrame 型のナニを再確認必要

てーか

腑にオチてない何かがあります。

  • 以前のエントリで_継続ってある特定の場所以降でやり残されている計算_みたいな事を書いたのですが、それってどうやって表現されているのか
    • ScmContFrame 型?
  • throw_cont_body 手続きで vm->cont が書き換えらえている件
    • ぶっちゃけ_書き換えて_良いのかなぁ、と

むむ

よく考えたらこの検討の始点は test/dynwind.scm の以下の試験だった。

;; continuation invoked while inline procedure is prepared.
;; a test to see call/cc won't mess up the VM stack.

(define (callcc-test2)
  (let ((cc #f)
        (r '()))
    (let ((s (list 1 2 3 4 (call/cc (lambda (c) (set! cc c) 5)) 6 7 8)))
      (if (null? r)
          (begin (set! r s) (cc -1))
          (list r s)))))
    
(test "call/cc (inline)" '((1 2 3 4 5 6 7 8) (1 2 3 4 -1 6 7 8))
      callcc-test2)

この試験マターだと vm->cont は書き換えられて構わないように見える。ただ、

  • r に s が ナニ
  • (cc -1) で巻き戻り

な瞬間、r は '() ではない、というのが現時点の理解では微妙。ちょっとスタックの状態とかを確認してみた方が良さげですが、あした頑張りまーす。

追記

上記の callcc-test2 を disasm してみた。

main_code (name=#f, code=0x8156d00, size=32, const=2, stack=20):
args: #f
     0 CONSTF-PUSH 
     1 CONSTN-PUSH 
     2 LOCAL-ENV(2)             ; (let ((cc #f) (r '())) (let ((s (list 1  ...
     3 CONSTI-PUSH(1) 
     4 CONSTI-PUSH(2) 
     5 CONSTI-PUSH(3) 
     6 CONSTI-PUSH(4) 
     7 PRE-CALL(1) 13
     9 CLOSURE #<lambda 0>      ; (lambda (c) (set! cc c) 5)
    11 PUSH-GREF-CALL(1) #<identifier user#call/cc>; (call/cc (lambda (c) (set! cc c) 5))
    13 PUSH 
    14 CONSTI-PUSH(6) 
    15 CONSTI-PUSH(7) 
    16 CONSTI(8) 
    17 LIST(8)                  ; (list 1 2 3 4 (call/cc (lambda (c) (set! ...
    18 PUSH-LOCAL-ENV(1)        ; (let ((s (list 1 2 3 4 (call/cc (lambda  ...
    19 LREF10                   ; r
    20 BNNULL 28                ; (null? r)
    22 LREF0                    ; s
    23 LSET(1,0)                ; r
    24 CONSTI-PUSH(-1) 
    25 LREF11                   ; cc
    26 TAIL-CALL(1)             ; (cc -1)
    27 RET 
    28 LREF10-PUSH              ; r
    29 LREF0                    ; s
    30 LIST(2)                  ; (list r s)
    31 RET 
internal_closure_0 (name=#f, code=0x81f1c20, size=4, const=0 stack=0):
args: #f
     0 LREF0                    ; c
     1 LSET(1,1)                ; cc
     2 CONSTI(5) 
     3 RET 

うーん。

;; a test to see call/cc won't mess up the VM stack.

ですか ...