読者です 読者をやめる 読者になる 読者になる

【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

インタプリタのクラス設計

自作インタプリタを少しずつ進化させて、複数のCPUやOSをサポートできるようになりました。クラス設計で試行錯誤した過程を残しておきます。

※ 文中の図はインラインSVGで描いています。(ソース

MINIX 2 (8086)

VM

最初はとにかく動作させることを優先して、設計は凝らずにベタ書きしました。VMクラスの中にインタプリタシステムコールを実装しました。

継承による実装の分離
VM VM8086 VMMinix2

CPUやOSを入れ替えられるようにするため、CPU部分とOS部分の分離に着手しました。

まず機能を分割して継承で結合させました。基底のVMクラスにはUNIXで共通に使えそうなシステムコールを残して、それを継承したVM8086クラスでCPUのインタプリタを、それを継承したVMMinix2クラスでMINIX 2依存のシステムコールを実装しました。

OSでCPUを挟んでいるのは過渡的な形態です。次の段階まではこれで通用します。

UNIX V6 (PDP-11)

VMUnix i8086::VM Minix2::VM PDP11::VM UnixV6::VM

基底クラスを共有する形でPDP-11とUNIX V6のクラスを追加しました。この段階ではOSでCPUを挟むような形がうまく適合できています。基底クラスはUNIX共通の機能を実装しているためVMUnixと名前を変え、派生クラスは名前空間に分離した上ですべてVMに名前を統一しました。

MINIXUNIX V7のシステムコール互換から出発したため、大半のシステムコールUNIX V6とMINIX 2の間で共通しています。どちらも16bitでプロセスのメモリモデルも似ています。CPUの命令セットとシステムコールのABIを追加実装した形です。

インポート

以前作成したPDP-11のインタプリタからコードを移植しました。

既に作りこんでいたクラスの継承関係にうまくはめ込むには、単純なインポートではなくリファクタリングが必要でした。その際にバグが入り込んで手こずりました。詳細はブログに書きました。

リファクタリングの成果として、アドレッシングモードの実装は以前よりもシンプルなものとなり、命令解析のキャッシングにより動作速度も向上しました。

CPUの分離

今回インタプリタを開発する目的は、UNIX V6の8086への移植をサポートすることです。カーネルの移植に先立ってコンパイラの移植から着手しますが、出力結果が正しく動作するかを確認するには、何らかの方法でバイナリを動作させる必要があります。そのため立ち位置の近いMINIX 2のインタプリタから始めて、システムコールをV6にすり寄せることで仮想的な8086版V6環境の実現を狙いました。

継承によるモデルでは親クラスが固定されているため、UNIX V6が継承するCPUを交換することができません。CPUとOSの継承関係を逆にすると、今度はOSが交換できなくなってしまいます。単一継承の限界です。

CPUとOSの継承関係を分離して、相互参照(下図の赤線)する形にリファクタリングしました。

VMBase PDP11::VM i8086::VM UnixBase Minix2::OS UnixV6::OS

単一継承での結合に比べてシステムコールにオーバーヘッドがありますが、実行時間の大半はCPU命令に費やされているので、ほとんど影響はありません。

UNIX V6 (8086)

UNIX V6の実装のうち、CPUに依存する部分(システムコールのABI)を分離して、8086用を追加しました。これにより目的だった仮想的な8086版V6環境が完成しました。

VMBase PDP11::VM i8086::VM UnixBase Minix2::OS UnixV6::OSBase UnixV6::OSi8086 UnixV6::OSPDP11

感想

結果だけ見ると、最初からクラス設計を決めておけば良かったようにも思えます。しかし当初は手探りで完成形のイメージもなかったため、適切に設計できたか疑問です。リファクタリングを重ねながらイメージを固めていく方法を採らざるを得ませんでした。

最後のステップ(8086版V6)は拍子抜けするくらいあっさりできました。リファクタリングを重ねて依存関係を整理したのが効果を発揮しました。

オブジェクト指向で設計しており、関数型の概念は取り入れていません。OSバンドルのコンパイラC++11をサポートしていない環境を考慮したためです。将来的にインタプリタの対応アーキテクチャを増やしていくことになれば、OSバンドルや動作速度にはある程度妥協して、他の言語に移行することも考えています。

UNIX V6の8086への移植はハッカソンとして開催します。

このインタプリタが役立つことを祈っています。