ユーニックス総合研究所

  • home
  • archives
  • interpreter-opcode

インタプリタのオペコードの実装

この記事ではインタプリタのオペコードの実装について解説します。

インタプリタの実装技術

インタプリタの実装ではおもに以下の種類の技術があります。

  • 字句解析処理
  • 構文木構築処理
  • 構文木実行処理

字句解析でソースコードを字句の列にして、それをもとに構文木を構築します。
そして構文木を構築したらその構文木をたどりながら言語を実行していきます。

オペコードの実装では以下の流れになります。

  • 字句解析処理
  • 構文木構築処理
  • オペコード構築処理
  • オペコード実行処理

字句解析と構文解析は同じです。
構文木を構築したら今度は構文木を使ってオペコードのバイト列を出力します。
そのオペコードのバイト列を実行して言語を実行します。

Pythonなどでは一度実行したスクリプトはオペコードとしてキャッシュファイルにしておき、次の実行ではそのオペコードを利用して処理を高速化しています。

オペコードとは?

オペコード(opcode)とは、バイト列で表現されるインタプリタの命令列です。
構文木を普通に実行するのに比べて高速にインタプリタを実行できると言われています。
高速になる理由は構文木をたどる処理が省略されるためです。

オペコードはアセンブラのような単純な命令をいくつも含んでいます。
オペコードの構築では構文木をもとにバイトの命令をバイト列に保存していきます。

オペコードの命令は例えばPythonでは以下のような命令があります。

LOAD_CONST  
BINARY_ADD  

LOAD_CONSTは値をスタックに積む命令です。
BINARY_ADDはスタックのトップから値を2つポップして加算を行います。
Pythonのオペコードはスタックを使って実装されています。
バイト列の命令を順次見ていきながら命令を実行して生成したオブジェクト、たとえば整数や実数などをスタックの上部にプッシュしていきます。

スタックを使うと計算処理を実現できるのは一部ではよく知られています。
詳しくは以下の動画でも解説しています。

C言語でスタック計算機を作る【Stack Calculator】 - YouTube

オペコードで高速化できるが・・・

オペコードである程度インタプリタを高速化できると言われていますが、実際にそういったアプローチのインタプリタは多いのですが、それでもJITコンパイラなどに比べると劣ります。

JITコンパイラは実行中のインタプリタで統計を取り、処理がたくさん呼ばれているコードを部分的に機械語にして実行できるようにするというものです。
「Just In Time」なので日本語にすると「実行時」になります。
有名な言語ではJavaScriptなどが実行時コンパイラで実装されています。
速度的にはJavaScriptはC++に匹敵すると言われています。
すごいぞ! JITコンパイラ!

現在実装中のインタプリタ

現在私の方でインタプリタを新しく開発しているのですが、オペコードで実装しています。
JITコンパイラも導入する予定ですので、それで得られた知見はまたブログに書きたいと思います。