バイトコード

バイトコード（）は、バイト指向の、中間表現のコードすなわち中間コードの総称である。バイトコードという名前は命令の構成がバイト指向であること、すなわち命令長がバイト可変長であったり、命令中のフィールドの区切りがビット単位でなくバイト単位になっていたり、といったことから来ている。特にJavaの場合オペコードが1バイトである（Javaバイトコードの記事を参照）。しかし、Java仮想マシンの命令体系をバイトコードと呼ぶことがJavaで広く一般的になったことから、前述のようなバイト指向でなくとも仮想マシン向けの命令体系全般をバイトコードと呼んでいることも多いバイトコードとは - IT用語辞典 e-Words。バイト単位でなくビット単位の場合は、ビットコードとも呼ばれる。ワード指向のためにワードコードという語を使っている例も見られる。

 存在意義 
ソースコードを直接解釈するインタプリタと同等の移植性を確保した上でのインタプリタのパフォーマンスの高さや、ソースコードの隠蔽が目的であれば、なんらかの中間表現で足りる。
それら中間表現の中でのバイトコードあるいはワードコードの意義は、得られるインタプリタの解釈実行パフォーマンスが最も高いことである。

多くのコンピュータにはバイト単位のメモリアクセスに特化した命令が用意されている。
あるいは、コンピュータのメモリアクセスは、そのコンピュータ固有の大きさのワード単位でのものが最も効率的である。
さらに、実ハードウェアの機械語のパフォーマンスを上げるため、機械語と同様に後続アドレスを順次読み込むメモリアクセスパターンは、多くのコンピュータのメモリシステムで最適化されている。
この、コンピュータにとって最も効率的なメモリ単位とアクセスパターンに、表現体系を合わせたものがバイトコードあるいはワードコードである。
このパフォーマンス上の利点から、現在の多くのインタプリタ言語は実際にはバイトコードにコンパイルされた後、バイトコードインタプリタによって実行される。

純粋なJavaのプログラムはプラットフォーム独立であり、実行環境（Java Runtime Environment, JRE）さえインストールされていればどこでも実行可能であるだけでなく、実行時コンパイラを使ってプロセッサ固有の機械語に随時変換することによってパフォーマンスを確保できることから、エンドユーザー向けにはバイトコードにコンパイルしてJARファイルとしてアーカイブしたものが配布されていることが多い。ソースコードを秘匿するプロプライエタリソフトウェアにも都合がよい。

また、中間表現の中でも実ハードウェアの機械語に最も類似したものなので、機械語に変換する直前の中間表現としても使われることがある。
バイトコードを使用した初期のコンピュータにはSystem/38があり、ソフトウェアのインストール時に機械語に変換された。

 スタックマシン vs レジスタマシン - その論点 
バイト指向でない中間コードもバイトコードも、その多くは、実ハードウェアの機械語と似た命令フォーマットや命令セットの構成をとっている。ただし、ハードウェアで実装されたプロセッサでは比較的、スタックマシンよりレジスタマシンの方が多いのに対し、ソフトウェアによる仮想機械や抽象機械ではJava仮想マシンなどスタックマシンも多いという特徴がある。なお、Luaのバージョン5やDalvik仮想マシンなど、レジスタマシンも多い。

 理論的観点 
「抽象機械」と呼ばれるような計算モデルとしての性格が強い機械の場合、理論的な扱いのためにスタックが使われているものもある。

 命令の粒度 
レジスタマシン型命令セットではオペランドの位置を命令内で明示する。これに対しスタックマシン型命令セットでは、暗黙のうちにスタックトップをオペランドとして使い、オペランドの位置を明示する領域が不要である。目的のオペランドがスタックトップにない場合にはオペランド移動のための命令を追加する。大まかに言えば、スタックマシン命令1個当たりの長さと機能は、レジスタマシン1命令内の個々のオペランドフィールド1個、またはコードフィールドと同等である。

このためバイトコード全体の長さには大差はなさそうだが、スタックマシンでは命令順を並び換えることでオペランド移動命令を略せる場合がある。レジスタマシンではオペランド指定は省略できないので、オペランド移動を省略した分だけスタックマシンの方が同等のプログラムを短く記述できる場合が多い。またデータキャッシュヒット率が高まるので、プログラムサイズ削減は実効速度改善にもなる。

しかしオペランド移動の省略を施しても、スタックマシンの方がレジスタマシンより命令数が多くなる。個々の命令が極めて単純な処理しか行わないバイトコードインタプリタでは、命令の種類を判定して分岐する処理が実行時間の大きな割合を占めるので、この点ではレジスタマシンの方が有利となる。

 命令間でのオペランドの受け渡し 
レジスタマシン型インタプリタでは番号で仮想レジスタを指定するが、多くの実機では実行時に物理レジスタを番号で参照することができないため、メモリ配列によって仮想レジスタが実装されている場合が多い。これに対しスタックマシン型インタプリタでは、ほとんどの命令のオペランドがスタックトップに決め打ちされ、参照すべき物理レジスタをコンパイル時に決定できるので、スタックトップ数個を物理レジスタで実装している。多くの実機ではレジスタ経由でのデータ受け渡しは1クロックでできるのに対し、メモリ経由でのデータ受け渡しは数クロックを要するので、直前の命令の結果を直後の命令が使う処理が連なった場合は、レジスタマシンは不利となる。

 ソースコードからバイトコードへの変換 
ALGOL以来、多くのプログラミング言語は文脈自由文法で記述でき、スタックマシンと類似したプッシュダウン・オートマトンで構文解析できる。このため、スタックマシン向けのコード生成器ならば、構文解析器と一体化させて省メモリ・高速なものにできる。

レジスタマシン向けの場合、有限のレジスタを使い回すレジスタ割り付けを行う必要がある。ただし、インタプリタの仮想レジスタはメモリ配列で実装されている場合が多い。このため、メモリ配列の大きさが許す限り、実機では非現実的な膨大な数の仮想レジスタを実装でき、その場合、レジスタの使い回しを省いてレジスタ割り付けを単純化することができる。レジスタ・ウィンドウも僅かなコストでレジスタ1本単位でスライドさせる柔軟なものが実装でき、スタックマシン向けと同様に構文解析器とコード生成器の一体化に役立つ。

 使用例 
 System/38 - TIMI (Technology Independent Machine Interface)
 Java - Javaバイトコード
 .NET Framework/.NET - 共通中間言語 (CIL)
 Raku
 Ruby 1.9
 JavaScriptの処理系の一部
 Microsoft DirectX（Direct3D）のシェーダーバイトコード（DXBC/DXIL）

 脚注 
 注釈 

 出典 

 関連項目 
 オブジェクトファイル
 命令セット
 Smalltalk
 Java仮想マシン
 中間表現
 Pコードマシン
 スレッデッドコード

Category:プログラミング
Category:仮想化