バグの原因を整理

(define a 1)
(display
 (let loop ([i 0])
   (if (= i 10)
       'done
       (let1 b a
         (loop (+ i b))))))

上の named let は jump に最適化される。
(if ...) の直前が jump 先、(loop (+ i b)) が jump 元。 closure の call/ret を繰り返さずに繰り返しを表現できるので速くなる。
ただし注意が必要で let1 で b という変数をスタックに積んでいるので、ジャンプの直前にその分スタックを捨てないといけない。そうしないと jump のたびにスタックにゴミが残る。
このため Gauche では jump 先から jump 元直前までに、スタックに積まれたものとそのサイズをコンパイル時に記録しておいて、jump の直前にスタックのゴミを捨てるインストラクションをはさむ。

Mosh でも同様の手法でうまく行くかと思い実装。しかし実装して動かしてみてから気付く。let1 で display レジスタが変わっているので復帰してあげないといけない。
レジスタを復帰するのは、ほぼ return に相当するので、どうしたものか。うまい方法ないかな。


3つ方針がある。

  • let 境界を越えていたら最適化 OFF にする
  • スタックに積まれた個数は分かるのでそこから、類推して実行時に display レジスタを復帰する。
  • ジャンプ先直前で frame を積む。あれ??