コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

バイトコード

出典: フリー百科事典『ウィキペディア(Wikipedia)』

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

存在意義

[編集]

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

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

Javaのプログラムは、利用者の環境を選ばずともパフォーマンスを確保できることから、ソースコードだけではなくバイトコードにコンパイルしたものも、標準的に配布されていることが多い。

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

スタックマシン vs レジスタマシン - その論点

[編集]

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

理論的観点

[編集]

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

命令の粒度

[編集]

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

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

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

命令間でのオペランドの受け渡し

[編集]

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

ソースコードからバイトコードへの変換

[編集]

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

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

使用例

[編集]

[編集]
  1. ^ 実機ではデコーダやエンコーダといった論理回路に向いたビットパターンのほうが好まれるといった細かい傾向の違いなどはある。

関連項目

[編集]