週刊nmosh - Gaucheにer-macro-transformerが入る / FFI VMの必要性

追記: see comment
Gaucheにer-macro-transformerが入ったようだ。

早速置き換えてみた:

が、今のところうまい書き方を見つけられていない。

oku@studio:~/repos/yuni$ run/gosh.sh _sanity.sps
*** ERROR: unbound variable: current-module
    While compiling "lib-stub/gauche/yuni/base/shorten.scm" at line 1: (define-library (yuni base shorten) (export ^_ ^z ^y ^x ^w ^v ^u ^t ^s ^r ^q ^p ^o ^n ^m ^l ^k ^j ^i ^h ^g ^f ^e ^d ^c ^b ^a ^) (import (scheme base) (yuni compat macro primitives) (yuni-runtime r7rs)) (include "lib/yuni/base/shorten.sls"))
    While loading "lib-stub/gauche/yuni/base/shorten.scm" at line 36
    While compiling "lib-stub/gauche/yuni/async.scm" at line 1: (define-library (yuni async) (export apply/async seq unquote quasiquote quote =>) (import (yuni scheme) (yuni base shorten) (yuni-runtime r7rs)) (include "lib/yuni/async.sls"))
    While loading "lib-stub/gauche/yuni/async.scm" at line 14
    While compiling "./_sanity.sps" at line 1: (import (yuni scheme) (scheme time) (scheme complex) (scheme inexact) (scheme write) (scheme lazy) (yuni async) (yuni core) (yuni base shorten) (yuni base match))
    While loading "./_sanity.sps" at line 8
Stack Trace:
_______________________________________

たぶん、不健全マクロをR7RSコード内で定義/使用することによって、 current-module への参照をどこかで挿入している。このコードはchibi-scheme版を基にしているが、たぶんChickenと同様の不健全マクロクロージャ問題を踏んでいる( http://d.hatena.ne.jp/mjt/20141011/p1 )。
(もっとも、nmosh 0.2.8ではsyntax-rules以外のマクロはyuniの内部で使用しないので、このコードが近い将来に使われることも無い。)

FFI VMの必要性

yuniFFIでは"FFI VM"と呼ぶ、Scheme VMよりも大幅に機能を限定したVMの存在を仮定している。FFI VMは、

  • asm.js( http://asmjs.org/spec/latest/ )同様の、固定長バッファに対する演算
    • int32 / int64 / double / float 演算
    • 基本的な数学関数の呼び出し
  • C同様のループ構文(for/while)と制御構造(if/switch/break/goto/return)
  • yuniFFIでバインドしたC APIの呼び出し

のみが可能なVMで、通常はSchemeコードに変換されてから実行される。
この必要性はあまり自明でないが、FFIフレームワークの移植性を高めるために役立つ:

  1. Schemeでのインタプリタ実装が容易である。Full Evalを備えないScheme処理系の場合でも、このVMSchemeレベルで逐次実行してもそれなりの速度で動作すると期待できる。
  2. Cでのインタプリタ実装が容易である。Schemeインタプリタが十分な速度を提供しないなら、Cインタプリタを提供することで速度を向上できる。
  3. Cトランスレータの実装が容易である。TinyCCのような組込みCコンパイラを使用してFFI VM部分をJITすることが考えられる。
    1. callbackとして使用できる。CからSchemeへのcallbackを許さない処理系であっても、FFI VMで生成したC関数をcallbackとして使用できる。
    2. 単体で動作できる可能性がある。Cトランスレータを使用することでCプログラムをFFI VM命令列から生成できる。

FFI VMの実装はnmosh 0.2.8の次のバージョンを目標にしていたが、諸般の事情で0.2.8での実装を目指すことになった。(SchemeとCのインタプリタ)
重要なポイントは、FFI VMを単なるbytevector処理用のライブラリとするのではなくFFIフレームワークの一部として提供する点と言える。yuniFFIで作成したバインディングを共用することで、FFI VMでそれなりに実用的なプログラミングが可能となる。
原理的には、Scheme処理系自体をFFI VMで実装できる。以前はそういうギャグということにしていたが、FFI VM自体の完成度を向上させるためには良い目標に見える。
FFI VMの最も実用的な用途は、"パフォーマンスの最後の伸び代"を提供すること。ゲームやインスタレーションSchemeで制作する上で、パフォーマンス要件の厳しいパートをCに追い出すことはよく行ったが、FFI VMを実装することでS式の世界を離れずにCへの追い出しを実現できると考えている。

yuniFFIを使用したクロス検証環境

諸般の事情というのは、yuniFFI / FFI VMの構成でボードの検証環境を準備する必要が有るため。

今回の案件は、

  • 某社製DSPターゲットボードを利用する必要が有る。
  • テキスト形式のスクリプトで、RTOSミドルウェアAPIをひととおり呼びたい。
  • 使用できるコンパイラ(& 開発環境)のライセンスはSolaris上で動作するノードロックのもの1つのみ。開発者の頭数と経験、配置を考えると.cを書いてコンパイルさせるのは難しい。
  • REPLのような対話環境が必要。しかし通信路はシリアルのみ。
  • デバッガが一切無い。LEDデバッグしかできない。
  • 実機は手元に無い。

(もしもコレが会社の仕事だったらライセンス買えよで終りな気もするが、まぁお金は大事なんで。。)
Luaとか他のスクリプトインタプリタでも良いじゃんという説も有り、実際バックアッププランとしてそちらも考えては居る(従来nmoshで書かれていたGUIJava製のWebUIに置き換えられた)。しかし、デバッガもJTAGエミュレータも無い状況ではコードは最小限にしたい。
FFI VMバイトコードの差し替えであればコンパイラを使用する必要は無いのでコンパイラライセンスの問題を解決できる。API DBをS式で書くところが面倒だが、これは教育を兼ねて他人にやらせるので。。
デバッグ手法としてはAPI呼び出しトレースをRAM上のリングバッファに書き出すことにした。意図せず停止した場合はwarm resetしてRAMに残った内容を見る方法でどうにかできる。