web-dev-qa-db-ja.com

バイトコードはどの程度正確に「解析」されますか?

バイトコードはどのように「解析」されますか?

バイトコードは、特定のプログラミング言語の構文のバイナリの中間表現であることは私の理解です。特定のプログラミング言語は、ソーステキストをバイトコードに変換し、それをファイルに書き込みます。これらの言語の仮想マシンはどのようにしてバイトコードを「解析」しますか?

この質問を絞り込むには、たとえばPythonのバイトコードを見てください。 Python仮想マシンが*.pycファイルからバイトコードの読み取りを開始すると、仮想マシンはどのようにして読み取り中のバイトのストリームを特定の命令に変換しますか?

仮想マシンがファイルからバイトコードを読み取るとき、バイトコードは1つの長いバイトストリームであると理解しています。それでは、バイトコードは便利なチャンクに分割されますか?オペコードとオペコード引数にどのように変換されますか?

たとえば、仮想マシンが2つの数値を追加するためにバイトコードを読み取っていたとします。 Virtal Machineは0x05という命令を参照します。これは、「2つの数値を加算する」ことを意味します。

各数値は異なるバイト数で表すことができるため、仮想マシンは、op0x05の引数を収集するために先読みする必要があるバイト数をどのようにして知ることができますか?

3
Christian Dean

あなたの混乱は、仮想マシンによって解釈されている言語としてバイトコードを考えることに起因すると思います。これは技術的にはそれを説明する正しい方法ですが、正しくないものについてのいくつかの仮定に導きます。

最初に理解する必要があるのは、バイトコードは machine code の一種であることです。 CPUが理解するマシンコードと異なるのは、この場合のマシンが仮想であることだけです(バイトコードを直接使用するハードウェアが可能です)。ターゲットマシンが仮想であるかどうかは、機械語のコンテキストではそれほど重要ではありません。

マシンコードは、コンピューターコードを簡単に解析できるように作成されているため、コンピューターで解析するのは簡単です。機械語とほとんどの人が精通している高級言語の主な違いは、後者は一般的に人間が使いやすいように構築されていることです。

これ 1997記事 on Javaバイトコードが役立つかもしれません。そのテキストから例を見てみましょう:

84 00 01

最初のバイト(オペコードと呼ばれます)は84です。 そのオペコードの意味を参照 すると、iinc(符号付きバイト定数でローカル変数#indexをインクリメント)であることがわかります。次の2バイトは、それぞれ変数のインデックスと量を示します。次に、JVMはその命令を受け取り、それを(言語仕様に従って)バイトコード命令に対応するマシン命令に変換します。

10
JimmyJames

バイトコードがデコードされます。それらはプロセッサ命令セットのように設計されています。バイトコードは可変長であるため、それらがどこにあるかはわかっていますが、それらをデコードするには、最初からデコードする必要があります(通常はメソッド)。

分岐命令(特に条件付き)に到達すると、分岐ターゲットまたはフォールスルー(次の命令)に従うことを選択できます。あなたが通訳をしているなら、あなたは前者をするでしょう、そして、JITするとき、あなたはおそらく後者をするでしょう。

エンコードされた各バイトは、実行する命令とその長さについて何かを示しています。単純で一般的な操作は、1バイト内にエンコードされます。他の操作は追加のバイトを使用します。デコーダーは、これまでにバイトの値を確認し、命令が完了したか、もう1バイトを取得するかを最小限に決定できます。一部のエンコーディングは、複数の追加バイトを示す場合があります。


Javaバイトコードクラスファイル形式、および可変長で非常に規則的なVAX命令セットアーキテクチャもご覧ください。Javaバイトコードはスタックアーキテクチャを使用しています、そしてかなり高いレベル(バイトコードであるため)ですが、VAXはレジスターマシンであり、低いレベルです(x86を参照することもできますが、これは規則性が低く、より複雑です、IMHO)。

4
Erik Eidt

ファイルには、実行可能バイトコード(およびそれに含まれる関数に関する情報)が置かれている場所と、定数データ(文字列など)が置かれている場所のバージョンに関する情報を含む小さなヘッダーがあります。 stackoverflowでは、Pythonのバイトコードに関する質問はすでに行われています。

バイトコード自体は非常に単純な構文であることがよくあります。最初の数バイトは、実行する必要がある操作と必要なオペランドを示します。バイトコードは、バイトごとにバイトを読み取るときに命令の明確な解釈ができるように設計されます。

操作ごとのバイト数を非常に明示的にする例を示すには、 SPIR-V があります。各命令の最初の4バイトワードは、2バイトの長さ+ 2バイトのオペコードとして構成されます。

3
ratchet freak