ruby-trunk-changes r37248 - r37260

今日も新しい YARV の命令の導入などメソッド呼び出し廻りで高速化のための修正がたくさんありました。また Hash#dup の変更による不具合修正もありました。

tenderlove:r37248 2012-10-18 09:24:00 +0900

r37232 で Hash#dup の実装を高速化のために変更した影響で Hash#dup で複製した Hash 同士が "==" で同値と判定されなくなっていたので、st_copy() 後に rehash するようにしています。

svn:r37249 2012-10-18 09:24:05 +0900

version.h の日付更新。

nobu:r37250 2012-10-18 10:29:54 +0900

self nil true false __FILE__ __LINE__ __ENCODING__ などの予約語? に代入する文は SyntaxError になることを確認するテストを追加しています。

nobu:r37251 2012-10-18 10:30:37 +0900

parse.y の代入文の左辺値の文法チェックでエラーになった時に続行していたのを正しくエラー処理に飛ばすようにしています。 r36973 の parse.y のリファクタリングで入ってしまった不具合の修正だそうです。

ko1:r37252 2012-10-18 14:22:13 +0900

コントロールフレームを積まないで呼べる C実装のメソッドを定義する関数やそのメソッドのタイプを rb_define_method_fast() -> rb_define_frameless_method()、VM_METHOD_TYPE_CFUNC_FAST -> VM_METHOD_TYPE_CFUNC_FRAMELESS などと fast -> frameless になるよう改名しています。

ko1:r37253 2012-10-18 14:33:31 +0900

コンパイル時に生成する rb_call_info_t::argc に callinfo のインラインキャッシュのインデックスを保持させていたのを rb_call_info_t::aux::index に格納するようにして、argc には引数の数を格納するようにしています。名前からして本来の用途になったようですが、argc は後で正しい値がセットされて、コンパイルの間だけ別の用途に利用するように使い回されていたのを aux ができて不要になったのでわかりやすくしたという感じだと思います。
ささださんから教えてもらったところ r37258 で追加するVM命令で rb_call_info_t::argc のセット(orig_argc からコピー)をスキップできるように最初から argc が正しい値になるようにしたそうです。

ko1:r37254 2012-10-18 15:04:02 +0900

r37252 で改名した rb_define_frameless_method() の宣言を include/ruby/ruby.h に追加しています。拡張ライブラリでも frameless なメソッドを定義できるんですね。

ko1:r37255 2012-10-18 15:14:39 +0900

vm_insnhelper.c のいくつかの static 関数に inline 指示子をつけています。つけなくても勝手に inline 化されるかと思ったけど gcc は inline 化してくれなかったので明示的に指定するようにしたようです。

nobu:r37256 2012-10-18 15:57:58 +0900

r37237 と r37253 の ChangeLog のエントリの行末の空白除去やインデントの修正。

nobu:r37257 2012-10-18 16:44:09 +0900

rb_add_method_cfunc() と rb_add_method_cfunc_frameless() で引数の数の制限に納まっているかのチェックを定義時にするようにしています。 C 実装のメソッドは通常は引数 15個まで、frameless なメソッドは1つまでしか引数を受け付けることができません。

ko1:r37258 2012-10-18 17:35:19 +0900

YARV に新しい特殊命令 opt_send_simple を追加しています。ブロック引数と splat 引数(*args のように複数の引数をまとめて受けつけるようなの)がない時に vm_caller_setup_args() の呼び出しをスキップできるので、専用の send_simple 命令にコンパイルするようにしています。
また obj.m= のような代入記号つきメソッドのコンパイル時に rb_call_info_t::argc を +1 するのに追随し忘れていたのを修正しています。

ko1:r37259 2012-10-18 18:41:55 +0900

r37259 の opt_send_simple 命令の導入で send 命令で falgs をみて vm_caller_setup_args() を呼ぶかどうかの分岐が不要になったので削除しています。
それから vm_caller_setup_args() で rb_call_info_t::blockiseq のチェックをしている if 文の条件に UNLIKELY() をつけていたのをやめています。ここは false じゃなくて true になる可能性が高いらしく、コメントで likely と書かれています。わかりやすいコメントありがとうございます。

ko1:r37260 2012-10-18 18:44:19 +0900

YARV の命令の実装で opt_send_simple の位置を send のすぐ後に移動しています。 insns.def は VM の実装方式によって各命令が関数になったり、大きな関数のなかの switch 文の case になったり、ただラベルがついてべったり処理が並んでいるだけになったりと実装方法が異なります*1。ただ処理が並ぶだけになった時は定義の順番がコンパイル結果の機械語命令の位置に影響する場合があります。(そうでなくてもある程度影響しそうですけど)
そして CPU が機械語命令をキャッシュする icache に載っていると命令の fetch が高速になるので、よく使う命令は近い場所にまとまっているほうが高速になりやすいことが期待できます。そういうわけで頻繁に使うことが期待される opt_send_simple も send と同じ一等地に置かれるようにしているということです。

*1:コンパイラのサポートがあるかどうかなどによって変化