クロスプラットホームの仮想化
QuickTransitのトランスレーション技法
異なるアーキテクチャのバイナリをトランスレーションする場合、通常、CPUの命令セットが1対1に対応することは無い。CISC(Complex Instruction Set Computer)からRISC(Reduced Instruction Set Computer)アーキテクチャに変換する場合には、RISCと比較してCISCの方が高度な命令を持つため、CISCの1命令を複数のRISC命令に変換する必要がある。逆にRISCからCISCへの変換の場合には、RISCの命令がCISCと比較して単純であるため、1対1で変換していくと非常に冗長な形になってしまいオーバーヘッドが大きくなる。
上記のような問題を解消するため、QuickTransitでは「ダイナミックバイナリトランスレータ」というモジュールを用いて、図2のような方法でトランスレーションを行っている。
ダイナミックバイナリトランスレータでは、コードを1命令ずつ変換するのではなく、ある程度のブロック単位で変換していく。取得したブロックは、一度「IR(Intermediate Representation:中間表現)」に変換する。
この段階で最適化処理を行い、効率的なコードに変換する。さらに頻繁に利用されるコード(HotPath)を判別し、再最適化しOptimized IR(最適化済み中間表現)に変換する。
最後に、最適化されたコードをターゲットのバイナリに変換する。このとき、HotPathとして判定されたコードはキャッシュされる。
要点は、一度IRに落とし最適化している点にある。ダイナミックバイナリトランスレータは、「デコーダ」「最適化カーネル」「コードジェネレータ」の3階層に分かれており、図2に示すようにそれぞれの段階にて以下のような処理を行っている。
・デコーダ:コードをブロック単位で読み込みIRにトランスレーション
・最適化カーネル:IRを最適化(HotPathは再最適化)
・コードジェネレータ:IRをターゲットのバイナリに変換。HotPathはキャッシュする
IRによって、さまざまなプラットホームで使えるような柔軟性を持たせ、最適化カーネルによる最適化とコードジェネレータによるキャッシュによって、トランスレーションの高速化を実現している。
QuickTransitの構造
アプリケーションをトランスレーションし、実際に異なるアーキテクチャのマシン上で実行させるために、QuickTransitは、ダイナミックバイナリトランスレータのほかに「OSコールマッパー」という仕組みを用意している。
これは、アプリケーションのシステムコールをトラップして、QuickTransitを実行しているホスト環境に合う適切なシステムコールにマッピングする仕組みである。適切なシステムコールが無い場合には、QuickTransitが独自にエミュレーションする。
また、実際にアプリケーションを実行するには、ダイナミックバイナリトランスレータとOSコールマッパーのほかに、アプリケーションで利用するライブラリ群も必要になってくる。OEMの製品に関しては、OEM先が用意しているライブラリを利用することになるのだが、パッケージ製品(QuickTransit for Solaris/SPARC to ○○○)の場合には、Transitive社が用意した「SolarisWorld」を利用する。
SolarisWorldは、Solaris/SPARCのライブラリ、コマンド、アプリケーションおよびそのほかのシステムファイル一式が含まれている。具体的には、「/soalris-sparc」 というディレクトリに、binや、lib、optなどのディレクトリが、あたかも実際のSolarisのルートディレクトリのように配置されている。
このSolarisWorldだが、OpenSolarisをもとにしているため、Transitive社のOpenSolarisのディストリビューションと言うこともできる。また、トランスレーションの対象となるアプリケーションのバイナリもこのディレクトリ配下に配置/インストールすることとなる。
それでは、実際に「QuickTransit for Solaris/SPARC to Solaris/x86-64」を使いSPARバイナリをx86で動作させる例を見ていこう。