msumimz's diary

RubyにJITコンパイラを実装する個人プロジェクトの情報発信ブログです。

開発方針について

JITコンパイルの生成元を、ASTからYARVインストラクションへ変更した話です。 JITコンパイルを行う元となる情報として、プログラムをパースした結果の構文木(AST)と、それをさらにコード化したYARVインストラクションがあります。今まではASTに基づいてCFG…

Array、Hash、Range、Stringリテラルに対応しました

配列の*による展開や、文字列埋め込みも普通に使えます。 あと、残っている大物は、 多重代入 ブロック メソッド引数 あたりでしょうか。

定数を実装しました

定数を実装しました。 module Outer class C X = 10 end end def m Outer::C::X end Jit.precompile Object, :m puts m # => 10 定数の値はコンパイル時に展開されます。定数の再定義やオートロードにも対応しています。 class_eval辺りと組み合わせると問題…

Visual Studio 2013に移行します [追記あり]

今まではVisual Studio 2010でもコンパイルできるように書いていたんですが、少しずつVisual Studio 2013に移行しようと思います。移行によって、主にC++11の機能で使えるものが増えます。詳細なリストはC++11 の機能 (Modern C++) のサポートにありますが、…

README.mdを書きました

いんちき英語でREADME.mdを書きましたので、Githubにプロジェクト概要とインストール手順が表示されるようになりました。https://github.com/msumimz/ruby/tree/rbjit合わせて、JITモジュールを定義して、precompileメソッドをモジュール関数にしています。…

メソッドの再定義に対応しました

メソッドが再定義された場合に、JITコンパイルされたメソッドが正しく動作するための仕組みを導入しました。この仕組みはさまざまな実装方針が考えられ、実行速度・メモリ使用量・コンパイル速度・実装の容易さの間でトレードオフがあります。とはいえ、実装…

precompileのエラーチェックをちゃんとしました

こんなコードを実行すると def m) [1,2,3] end precompile(Object, :m) こんなエラーになります(配列リテラルをサポートしていない)。 $vc10/Debug/miniruby test.rb test.rb:5:in `precompile': m:2: Node type NODE_ARRAY is not implemented yet (Argum…

フルRubyのビルドに対応しました

今まではminirubyのみだったのですが、今回、フルのRubyのビルドに対応しました(Windowsの32bit版のみ)。ベースとなるRubyのバージョンは2.1.0です。LLVMはバージョン3.4を使っています。ビルドにはVisual Studio 10以降が必要です。ビルド手順は、以下の…

最初の最適化:型解析とメソッドのインライン化

前回の投稿から期間が空いてしまいました。実装にはいろいろ不十分なところも多いのですが、きりがないので記事にすることにします。前回のベンチマークでは、JITを実装したものの、単純なJITコンパイラではMRIのインタープリタによる実行速度に勝てないとい…

LLVMのJITサポートの現状

前回の続きで、せっかくなので、LLVMのJITサポートの現状をまとめておきます。現行のLLVM 3.4のJITコンパイラサポートは、古くから存在するシンプルな仕組み(old JITと呼ばれます)と、MCJITと呼ばれる新しい仕組みの2種類が併存しています。今後は、old JI…

LLVMの今後

5月25日のInfoQに、こんな記事が載っていました。AppleがLLVM JITを使用してWebKitのJSエンジンをスピードアップ http://www.infoq.com/jp/news/2014/05/safari-webkit-javascript-llvm記事の内容自体はLLVMの活用事例ということで結構な話なのですが、気に…

復帰報告

ようやく仕事の繁忙期が終わりまして余裕ができましたので、JITコンパイラの開発を再開したいと思います。その前に、リハビリてがら小さなツールをつくったりしました。Autocompo https://github.com/msumimz/autocompoちょっとした画像合成ツールです。写真…

メソッド引数とselfを実装しました

久しぶりの更新になります。遅々として進みませんが、開発が行き詰まっているわけではなく、仕事が多忙であまり時間がとれないためです。*1さて、前回はベンチマークを取り、その結果、単純にJITコンパイルしただけで高速に実行されるわけではないことが判明…

先ほどのベンチマークのコードがどのようにコンパイルされたか

参考までに、先ほどのコードがどのようにコンパイルされたか見てみましょう。元のメソッドは下記のとおりです。 def m1 i = 1 sum = 0 while i <= 10000 sum += i i += 1 end sum end JITコンパイルされた結果は以下の通りです。*1 03450016 mov edi,3 ; i =…

最初のベンチマーク

これまでにif、while、メソッド呼び出し、ローカル変数のコンパイル処理を実装してきました。すでに簡単なプログラムが動くくらいになっていますので、この辺りでJITコンパイルされたコードの速度を確認してみたいと思います。コードは以下の通りで、1から10…

whileを実装しました

こんなコードが動きます。 def m1 i = 1 sum = 0 while i <= 10000 sum += i i += 1 end sum end precompile Object, :m1 puts m1 # => 50005000 たかがwhileにどれだけ時間かかってるんだという感じですが、機能追加に合わせて周辺コードを追加・変更してい…

メソッド呼び出しを実装しました

対応したのはMRIの内部でNODE_CALLと呼ばれる、レシーバを指定した形式です。そのうち、引数が単純でブロックを取らないもの限定です。足し算なども内部ではメソッド呼び出しですので、例えば以下のコードが動きます。 def m 1 + 2 end precompile Object, :…

ローカル変数参照を実装しました

ローカル変数参照を実装しました。以下のコードが実行できます。 def m if true a = 10 else a = 20 end a end precompile Object, :m puts m # => 10 LLVMは優秀なので、上のメソッドはこんなコードにコンパイルされます(x86の場合)。 mov eax, 15h ret 1…

if文を実装しました

ついでにtrue/false/nilリテラルも実装しています。 以下のコードが動くようになりました。 def m if 1 10 else 20 end end precompiled Object, :m puts m # => 10 実装した構文はifだけですが、内部でコントロールフローグラフをSSA形式というものに変換す…

最初のJITコンパイラを実装しました

JITコンパイラの最初のバージョンが動くようになりました。このバージョンのminirubyには、Object#precompileというメソッドが追加されています。これは precompile <クラス>, <メソッド名(シンボル)> という書式で呼び出すことで、で指定されたメソッドの…

clangのアセンブリをIntel形式で出力する

clangで-Sオプションをつけてアセンブリを出力する場合、既定でAT&T形式になります。これをIntel形式にするには以下のオプションを使えばよいようです。 clang -S -o - -mllvm -x86-asm-syntax=intel test.c '-mllvm'というのは、clangのインフラであるLLVM…

githubにssh keyを設定

githubにpushしようと思ったところ、なぜかid/password認証に失敗します。githubのヘルプページを見ると、gitはバージョン1.7.10以上を使えと書いてあります。Cygwinのgitはバージョン1.7.9で、このためでしょうか。アップデートしようとしましたが、Cygwin…

githubにプロジェクトを作成

今まではwww.ruby-lang.orgからv2.1.0のソース一式をtar.gz形式でダウンロードして手元でいろいろいじっていたのですが、そろそろコードを書き始めています。今後のバージョン追随のためにも、MRIのソースコードとはなるべく独立するようにしていますが、多…

MRIソースコードを読む その1 メソッド定義の実装(下)

vm_method.c:rb_add_method()ですが、エラーチェックしながらデータを設定しているだけです。せっかくですのでJITコンパイラを実装するために必要そうな知識を整理しておきます。メソッド定義に関係するデータ構造は、rb_method_entry_tとrb_method_definiti…

MRIソースコードを読む その1 メソッド定義の実装(中)

さて、(上)に続いてメソッド定義の実装を見ていきます。core#define_methodの実体はvm.c:m_core_define_method()です。 #define REWIND_CFP(expr) do { \ rb_thread_t *th__ = GET_THREAD(); \ th__->cfp++; expr; th__->cfp--; \ } while (0) static VALU…

MRIソースコードを読む その1 メソッド定義の実装(上)

自分向けの備忘録として、MRIのソースコードを読んだ結果メモを記録しておきます。以下のソースコードは def m 1 end 次のISeqにコンパイルされます。 == disasm: <RubyVM::InstructionSequence:<main>@-e>====================== 0000 trace 1 ( 1) 0002 putspecialobject 1 0004 putspecialobj</rubyvm::instructionsequence:<main>…

Ruby Under a Microscope買いました

他の方のレビューでは、ソースコードと結びつけた記述は少ないそうですが、スタックフレームの取り扱いやブロックの処理などのイメージをつかむのに役立ちそうです。Ruby Under a Microscope: An Illustrated Guide to Ruby Internals作者: Pat Shaughnessy…

RubyでASTやIRを表示する

JITコンパイラを書くには、まずRubyの生成するASTを調べる必要があります。そのためのツールとして、以前に読んだ「Rubyソースコード完全解説」でnodedumpという外部ライブラリを使っていました。 じゃあそれを使おうと思ってググってみましたが、どうも最新…

デバッガにブレークするメソッドを定義する

MRIのコードを読む準備として、デバッガにブレークするメソッドをObjectクラスに定義します。 minirubyだけでは外部ライブラリを構築できませんので、object.cに直接書いてしまいます。 まず、以下のコードをobject.cのInit_Object()の前に追加します。 stat…

Visual Studioプロジェクトを作成する

Windows版のRubyをVisual Studioでビルド・デバッグできるようにVisual Studioのプロジェクトを作成します。 ソース配布ではnmakeを使ってビルドするようになっていますので、Makefileを解析して同じビルド手順を再現します。 なかなか手ごわいMakefileです…