ruby-trunk-changes r43615 - r43636

今日は大きめの変更がありました。まず String#freeze が文字列リテラルに対して呼ばれた時にコンパイル時に特別扱いして、同じ文字列には常に同じオブジェクトを返すようにする機能が追加されました。これに伴ない、文字列リテラルの "f" suffix で freeze した String オブジェクトを共有する機能は削除されました。また例外オブジェクトに Exception#cause というメソッドが追加されて、rescue 節で発生させた例外には、その時点の $! が自動的に格納されて簡単に参照できるようになりました。

nobu:r43615 2013-11-09 22:34:53 +0900

昨日追加された ObjectSpace.dump_all の修正の続きです。dump_output() の引数 filename の const を外しています。 mkstemp(3) が char * を要求するためとのこと。

nobu:r43616 2013-11-09 22:35:01 +0900

ObjectSpace.dump_all のテストに無引数で呼び出して一時ファイルに書き出した時のテストケースを追加しています。

nobu:r43617 2013-11-09 22:35:39 +0900

r43609 で tool/file2lastrev.rb から分離した tool/vcs.rb を tool/rbinstall.rb でも利用して最後のコミットの更新日時を取得して gemspec の date をセットするようにしています。同梱されている gems パッケージの gemspec がビルドするたびに変化してしまう問題の追加対応みたいです。 [ruby-core:58193] [Bug #9085]

zzak:r43618 2013-11-10 00:34:25 +0900

lib/racc/rdoc/grammar.en.rdoc の typo 修正。 [ruby-core:58153] [Bug #9077]

svn:r43619 2013-11-10 00:34:30 +0900

version.h の日付更新。

nobu:r43620 2013-11-10 00:34:30 +0900

gc.c の define_final() と rb_define_final() で共通していた call メソッドが呼べるかどうか確認する処理を should_be_callable() という関数として抜き出して共有するリファクタリング

nobu:r43621 2013-11-10 00:36:46 +0900

r43620 で切り出した should_be_callable() で call が private メソッドでも呼び出せるようにしています。

ko1:r43622 2013-11-10 00:43:30 +0900

benchmark/gc/gcbench.rb で実行している ruby インタプリタGC::OPTS を表示するようにしています。

ko1:r43623 2013-11-10 01:35:54 +0900

malloc() 由来の GC の起動の時は LazySweep を無効にして全ての未使用になったオブジェクトの sweep を実行するようにしています。 LazySweep は mark されなくて解放予定のオブジェクトが新たなオブジェクト確保まで実際に sweep されずに、そのオブジェクトが持っているヒープ上のメモリ領域も解放されないまま残るためメモリ容量がなかなか減らないという特性があり、malloc() 由来の時はできるだけメモリ使用量を抑えるように即時 sweep するようにしています。

nobu:r43624 2013-11-10 01:37:46 +0900

tool/rbinstall.rb で gemspec ファイルの最終更新時刻の取得に失敗して例外が発生した時の対処を追加しています。

nobu:r43625 2013-11-10 01:46:17 +0900

テスト用のユーティリティ test/ruby/envutil.rb の EnvUtil#under_gc_stress に省略可能な引数を追加して GC.stress= で設定する値を指定できるようにしています。

nobu:r43626 2013-11-10 03:12:39 +0900

ファイナライザのテストを子プロセスを起動して実行するようにしています。ファイナライザを確実に実行させるにはプロセス終了まで待たないといけない場合もあるのでとのこと。

charliesome:r43627 2013-11-10 06:17:06 +0900

String の freeze について文字列リテラルに対して呼ばれた時には命令列へのコンパイル時点で特別扱いをして、同じ内容の文字列に対する freeze は同一のオブジェクトを返すようにするしくみを導入しています。

a = "str".freeze
b = "str".freeze
a.object_id == b.object_id

上のようにするとこれまで a と b は別のオブジェクトだったので object_id の比較は false でしたが、今後は同じオブジェクトを返すようになるので true になります。
なおこの特別扱いは文字列リテラルに直接 freeze が呼ばれた時だけコンパイル時から別の処理にしているので、一旦変数に代入したりメソッド返したものに freeze を呼んだ時は別のオブジェクトのままです。

a = "str"
b = "str"
a.freeze.object_id == b.freeze.object_id # => これは false

"str"f のような f suffix で freeze された文字列を共有するようにする仕様が追加されていましたが、f suffix はその後やっぱりやめにして String#freeze に最適化をおこなうようにするという方針になりました。 [ruby-core:57705] [Feature #8992]

nobu:r43628 2013-11-10 06:21:08 +0900

r43627 の ChangeLog エントリの行末の空白除去。

charliesome:r43629 2013-11-10 06:28:05 +0900

標準添付ライブラリ e2mmap.rb の rdoc コメントの typo 修正。 https://github.com/ruby/ruby/pull/438

zzak:r43630 2013-11-10 07:42:20 +0900

標準添付ライブラリ weakref.rb の rdoc 用コメントの typo 修正。 https://github.com/ruby/ruby/pull/439

nobu:r43631 2013-11-10 08:03:11 +0900

ファイナライザの設定/削除用の C API の関数名を rb_define_final/rb_undefine_final から rb_define_finalizer/rb_undefine_finalizer に変更して include/ruby/intern.h に宣言を追加して外部の拡張ライブラリから直接利用できるようにしています。

zzak:r43632 2013-11-10 08:13:35 +0900

標準添付ライブラリ drb の rdoc コメントでのサンプルコード内でのログファイルのファイルパスをファイル名に使えるものにする置換の正規表現を修正しています。 "." と "/" を置換していましたがバックスラッシュや ":" も置換するようにしています(Windows 向け)。 [ruby-core:58137] [Bug #9074]

zzak:r43633 2013-11-10 08:38:14 +0900

Thread#thread_variable_get の rdoc 用コメントで Thread#[ ] を参照しているコメントが重複していたので後のを消しています。

nobu:r43634 2013-11-10 15:13:02 +0900

文字列リテラルの "f" suffix 機能を revert しています。 r43627 で String#freeze の最適化機能が代替として導入されたのに伴ない "str"f の ような f suffix は廃止されています。 [ruby-core:57966] [Feature #9042]

kazu:r43635 2013-11-10 19:17:44 +0900

r43627 の ChangeLog エントリの typo 修正。

nobu:r43636 2013-11-10 22:16:33 +0900

Exception#cause というメソッドを導入して、例外オブジェクトは rescue 節で raise された時にはその時点での例外オブジェクトを保持して、cause メソッドで元となった例外オブジェクトにアクセスできるようにしています。 [ruby-core:54185] [Feature #8257]

おお、この Feature チケット見逃していましたが、これは結構ありがちな要求で、定義した例外に元の例外のメッセージを埋め込んだり backtrace を偽装したりしてなんとかしていたと思うんですけどこういう対処方法もありますね。
つまり以下のような rescue で例外を捕捉して別の例外を投げ直す時に、元となった例外を簡単に取得できるようになります。

def foo
  begin
    do_something()
  rescue
    raise MyError, "something wrong"
  end
end

begin
  foo
rescue MyError
  $!.cause # => do_something で発生した元々の例外が取得できる
end

これはたぶんとても便利! JRuby の Charles Nutter の提案です。rescue で例外発生させると常に参照が発生するので例外オブジェクトが GC されにくくなる点がちょっとだけ気になりますが、例外がそんなに長生きすることはないと思うのであまり影響ない、かも……(RGenGC で旧世代へ promote しやすくなるという点はあるかもしれないですね)。