yomikomu(0.4.1)のコードリーディングをしました。

コードリーディングの前にRubyVM::InstructionSequence.load_iseqの説明をします。

Rubyでloadやrequireをすると

  1. RubyVM::InstructionSequence.load_iseqが定義されている場合、load_iseqを実行
    • 戻り値がnilであればファイルから読み込んでパース・コンパイルして命令列に変換して実行
    • 戻り値がnilでなければ、それを命令列として実行
  2. load_iseqが定義されていない場合は、ファイルを読みこんでパース・コンパイルして命令列に変換して実行

というフローでファイルがロードされます。

例えば以下のようなコードで

これを実行すると、requireの度にRubyVM::InstructionSequence.load_iseqが呼ばれ、以下のように出力されます。

上の例だとputsの戻り値=nilなので通常通りファイルがコンパイルされますが、ここでiseqを返してあげることでRubyに命令列を直接読み込ませることが可能です。

それではコードを読んでいきます。yomikomuはlib/yomikomu.rbのワンファイルになります。

環境変数が設定されている場合、RubyVM::InstructionSequence.load_iseqが呼ばれます。load_iseqはYomikomu::STORAGE.load_iseqを呼びます。

Yomikomu::STORAGEはストレージのクラスで環境変数によって変わります。

デフォルトはFSStrogareなので、以下FSStorageに関して見ていきます。

FSStorageはBasicStorageを継承しています。BasicStorage#load_iseqは以下のように定義されています。

コンパイルしたiseqが既に存在していて(compiled_iseq_exist?)、直近にコンパイルされたものであれば(compiled_iseq_is_younger?)、コンパイルされたiseqを読み込みRubyVM::InstructionSequenceのインスタンスを返します。そうでなければ、環境変数によって設定されるYOMIKOMU_AUTO_COMPILEがtrueであれば自動的にコンパイルを行い、YOMIKOMU_AUTO_COMPILEが設定されていなければnilを返し通常のファイル読み込み・パース・コンパイルを行います。

compiled_iseq_exist?やcompiled_iseq_is_younger?は以下のように定義されています。

コンパイルしたファイルが存在し、コンパイル時よりもあとにファイルが更新されていない場合に読み込むようになっています。

read_compiled_iseqはFile.binreadでファイルの読み込みをしています。

参考