ruby-trunk-changes r43958 - r43983

今日は Module をたくさん include する時や loaded features が多数ある時の GC コストの軽減のための最適化や RDoc の最新版マージ、再帰的な参照構造をもつオブジェクトの hash の値がその循環構造のどこで取っても同じになるようにする修正などがありました。

usa:r43958 2013-12-02 22:31:14 +0900

r43950 の Windows 環境での環境変数取得の修正でテストが失敗していたので再修正しています。 [ruby-core:58774] [Bug #9195]

drbrain:r43962 2013-12-03 09:42:49 +0900

RDoc の最新版をマージしてバージョンを 4.1.0.preview3 に更新しています。差分は小さいですがよくわからなくて、定数のドキュメントの有無をチェックするメソッドを修正しているようです。

svn:r43963 2013-12-03 09:42:57 +0900

version.h の日付更新。

drbrain:r43964 2013-12-03 10:44:41 +0900

拡張ライブラリ openssl の ext/openssl/lib/openssl/buffering.rb の magic comment に coding: binary を指定してこのスクリプト内の文字列リテラルが ASCII-8BIT エンコーディングとして扱われるようにしています。 [ruby-core:57906] [Bug #9028]

nobu:r43965 2013-12-03 12:18:46 +0900

r43958 のさらに追加修正。 w32_getenv() の定義に static を付加しています。

nobu:r43966 2013-12-03 12:18:49 +0900

SIGSEGV や SIGBUS 受信時に rb_bug() で強制終了する時に問題となったメモリアクセスのアドレスをメッセージに含めるようにしています。

nobu:r43967 2013-12-03 12:18:52 +0900

r43962 の RDoc の更新で r43006 の拡張ライブラリの時に nil に対して documented? が呼ばれる件の対応が消えていたので再々適用しています。 upstream にパッチ当てないとまた消えるような気が……と思ったらこの後取り込まれたようですね。 https://github.com/rdoc/rdoc/commit/a883e14b8bd0eb4714466e7d9bd5068619c4c998

tmm1:r43968 2013-12-03 12:40:56 +0900

文字列リテラルや内部的に利用されている文字列で freeze + 共有化された文字列を作る rb_fstring() で文字列オブジェクトの共有化のために st_table を管理する方法を st_lookup() と st_insert() を使う方法から st_update() を使う方法に変更して効率化しています。 けど existing が 偽の時は ST_STOP を返したほうがいいような。 fstr_update_callback() で value を書きかえてないので動作上は問題ないと思いますけど。

glass:r43969 2013-12-03 13:55:51 +0900

Array#uniq や uniq! の実装で内部的に Hash を作ってそこに登録して重複を省いていったあと取り出す時にキーではなく値のほうを取り出すようにしています。 r43194 のあたりで Hash オブジェクトを使うようにした影響で、 Hash の aset([]=)はキーが文字列だと dup+freeze した文字列を使うようになっているのに影響されて uniq で String オブジェクトが freeze される不具合が発生していたのを修正しています。 [ruby-core:58809] [Bug #9202]

glass:r43970 2013-12-03 14:13:19 +0900

r43969 の変更の結果 Array#uniq にブロックが渡された時も渡されなかった時も Hash の値のほうを取り出すことになったので不要になった関数やコードを削除しています。

nobu:r43971 2013-12-03 15:08:19 +0900

r43966 で SIGSEGV や SIGBUS 時にエラーになったメモリアクセスのアドレスを表示するようにしたために SEGV 時のハンドラのテストが失敗していたので、テストを追随させています。

naruse:r43972 2013-12-03 15:30:58 +0900

NEWS ファイルの String#scrub の記述のところに、以前のバージョンで利用したい時は string-scrub.gem という gem パッケージでメソッドが追加されることを追記しています。

tmm1:r43973 2013-12-03 17:11:07 +0900

struct RClass の持つ method entry のテーブル m_tbl の持ちかたを変更して struct RClass::m_tbl から struct method_table_wrapper という構造体を途中にはさんで struct RClass::m_tbl_wrapper::tbl という構造に変更しています。またこの変更に追随するためアクセス用のマクロなども追加/変更しています。 この struct method_table_wrapper は serial というメンバも持っていて、GC mark 時に GC 回数を格納しておいて同じ GC の mark 時に st_table の mark 処理を skip するようにしているようです。これは Module を include した時などに Module と IClass で m_tbl を共有するため、同じ st_table を何度も mark 処理する無駄を省くため、構造体を挟んでそこで重複した mark は止めるようにして mark を高速化しているそうです。ChangeLog に大規模なアプリで minor GC 時のマーク処理を 30% 減らせたという記述があるので Module をたくさん使っている時は効きそうですね。

tmm1:r43974 2013-12-03 17:13:31 +0900

load.c で loaded features への挿入時に一時的に利用する配列オブジェクトを rb_ary_tmp_new() で作成していましたが、ObjectSpace を利用するため GC のマークが行なわれるのを防ぐため xcalloc() で直接メモリ確保して RVALUE (struct RArray として確保していますが)として Ruby のメモリ管理の heap とは別のところにオブジェクトを作っています。格納しているものが Fixnum のみで GC で管理する必要がないので可能な方法なのでしょう。 過去にも同様にスタック上にダミーの slot を置いたダミーのオブジェクトを作る手法が使われてたことがあったと思いますが(確か VM の初期化のあたりだったと…)、かなり思いきった方法ですね。これそんなに効くのかなぁ。 ChangeLog によるとやはり大規模なアプリケーションで minor GC の時間が 15% 減るということですが、大規模な Rails アプリとかだと loaded features がとても大きくなるので効くのかなぁ。 struct RBasic::flags の初期化(T_ARRAY の型の指定)が直に書かれているあたりとかちょっと座りの悪さを感じますね。 rb_ary_XXX() を便利関数として使いたいがためだけのオブジェクト化なのでいいんでしょうけど。 [ruby-core:58805] [Bug #9201]

glass:r43975 2013-12-03 20:19:06 +0900

r43942 で Hash の rehash 時のメモリリーク修正時に st_table 保持用の Hash オブジェクトを生成するのに rb_hash_new() ではなくてより内部的な hash_alloc() を利用するように変更しています。 [ruby-core:58728] [Bug #9187]

nari:r43976 2013-12-03 20:24:11 +0900

Object#clone 時に新規に作成したオブジェクトの struct RBasic::flags に rb_obj_alloc() から返ってきた時点で既に GC が発生していて RGenGC 用の FL_PROMOTED や FL_WB_PROTECTED のフラグが立っている可能性があり、コピー元のフラグを or する前にこれらのフラグがクリアされてしまっていたので残すようにしています。

nobu:r43977 2013-12-03 21:08:39 +0900

r43975 の ChangeLog エントリに hash_alloc() を利用するようにした理由を追記しています。 klass を空にすることで ObjectSpace から隠すためだそうです。

a_matsuda:r43978 2013-12-03 21:14:22 +0900

標準添付ライブラリ net/smtp の rdoc 用コメントの typo 修正。 raies -> raises

nobu:r43979 2013-12-03 21:53:18 +0900

大域脱出 throw - catch の catch の C API である rb_catch() の亜種で rb_catch_protect() という API を追加しています。 これは rb_catch() と rb_protect() を合わせたようなもので throw 以外の例外などの大域脱出も捕捉することができます。追加された第4引数の stateptr にポインタを渡すとそこに state を格納して返します。従って呼び元では state をチェックして必要なら再度 JUMP_TAG() で例外などを伝播させなくてはいけません。

nobu:r43980 2013-12-03 22:18:30 +0900

r43859 や r43860 での Object#hash がネストした構造を持つオブジェクトで再帰するのとチェックするようにしたのを再修正しています。 rb_hash() で rb_exec_recursive_paired() つきで呼ぶようにすることで個別の hash 関数で rb_exec_recursive_paired() を使わなくて済むようにしています。

nobu:r43981 2013-12-03 22:32:24 +0900

rb_hash_recursive() という関数を追加して、再帰的な参照構造をもつオブジェクトの hash 値がそのどこで hash を取っても同じ値になるようにしているみたいです。 r43860 の解説で書いたように同じ構造の時に hash の値が同一になることを保証するのが困難だったのをなんとかしているみたいです。

nari:r43982 2013-12-03 23:14:09 +0900

r43976 の Object#clone 時の flags のコピーの修正。 FL_WB_PROTECTED はコピー元のオブジェクトから引き継がないようにしています。

nobu:r43983 2013-12-03 23:48:20 +0900

BSD 系の環境で利用可能な malloc_size(3) というライブラリ関数を利用して malloc() 等で確保したメモリ領域のサイズを取得するようにしています。 r43760 あたりで導入した malloc_usable_size(3) と同様に利用しています。 へーこういう関数結構いろんな環境であるんですね。 なお Mac OS XBSD 系列なので malloc_size() が存在するようです。
[追記]ChangeLog には BSD にあるって書かれているのですが、今のところ実際に存在が確認されているのは Mac OS X だけらしいので、どちらかというと Mac OS X 向けの追加だそうです。[/追記]