ruby-trunk-changes r38132 - r38144

今日はコンパイラの最適化によってGCに必要なマシンスタックの情報が取れなくなる可能性があった不具合の修正と TracePoint の inspect での表示を賢くする変更などがありました。

ko1:r38132 2012-12-02 02:47:37 +0900

TracePoint#inspect の定義を追加してデフォルトの表現ではなくいい感じに文字列化されるようにしています。
いい感じにというのは通常時は enable, disable の状態が表示されるだけですが、イベントが発火してフックが呼ばれた時にはそのイベントの種類に応じた情報とファイル名、行番号が表示されるようになっていて、試しに使ってみると以下のようになりました。

tp = TracePoint.new{|tp| p [tp.event, tp] }

tp.enable do
  def m
    yield
  end
  m { print "Hello World!\n" }
  GC.start
end

*1

これを実行すると以下のようになります。

[:b_call, #]
[:line, #]
[:c_call, #]
[:c_return, #]
[:line, #]
[:call, #]
[:line, #]
[:b_call, #]
[:line, #]
[:c_call, #]
[:c_call, #]
Hello World!
[:c_return, #]
[:c_return, #]
[:b_return, #]
[:return, #]
[:line, #]
[:c_call, #]
[:c_return, #]
[:b_return, #]

こうしてトレースを表示するだけで夢が膨らみますね。 TracePoint もすばらしい新機能です。

ko1:r38133 2012-12-02 05:07:58 +0900

ISeq#line_trace_all, ISeq#line_trace_specify で ISeq の trace point を探索する時に line のイベントの trace 命令のみカウントするように修正しています。

kosaki:r38134 2012-12-02 06:15:01 +0900

gc.c のマシンスタックの終端(現在のスタックポインタ)を取得する SET_MACHINE_STACK_END() で利用しているインラインアセンブラに volatile 修飾子を付けています。よくわかりませんがコンパイラ最適化で期待した結果が得られないのを防いでいるそうです。 [ruby-dev:46665] [Bug #7468]

drbrain:r38135 2012-12-02 07:24:53 +0900

rdoc がパース対象のファイルを検出する方法として、拡張子の他に1行目に "-*- rdoc -*-" という modeline を含んでいたら rdoc で解釈すべきファイルとして扱うようにする機能が追加されています。

tarui:r38136 2012-12-02 11:47:19 +0900

r38134 の ChangeLog に ML と チケットの参照を追記しています。

kazu:r38137 2012-12-02 12:30:02 +0900

r38077 の ChangeLogtypo 修正。

zzak:r38138 2012-12-02 16:45:17 +0900

WeakMap の rdoc に weakref.rb で使うために作られたもので直接使われることは意図していないことを追記しています。

zzak:r38139 2012-12-02 16:48:42 +0900

標準添付ライブラリ weakref.rb の rdoc のサンプルを少しきれいにしたり、WeakRef の使いかたについての詳しい例を追記したりしています。使用例がいいですね。この例で他の変数から参照されていて生き残っているオブジェクトに対する参照でも WeakRef 経由の参照が消えてるのはどっちかというと key に使っている String が GC されるからじゃないかなって気がしますけど。

zzak:r38140 2012-12-02 16:57:45 +0900

r38139 の WeakRef のコード例の typo 修正。

tarui:r38141 2012-12-02 17:45:14 +0900

スレッドの切り替え時に GC でマークするためにマシンスタックの情報を保存する RB_GC_SAVE_MACHINE_CONTEXT で、スタックポインタを保存する SET_MACHINE_STACK_END() の実行を、その他の情報を保存する rb_gc_save_machine_context() の中に入れています。関数の内外でスタックポインタが違うはずで、関数呼び出しでレジスタの値をスタックにのせた上で変更された結果が保存されて、スタックポインタが rb_gc_save_machine_context() の外側までのものだとその部分が保護されない可能性があるということかと思います。

tarui:r38142 2012-12-02 17:56:27 +0900

しかし何か問題があったらしくて r38141 は revert されています。

ko1:r38143 2012-12-02 18:57:47 +0900

あちこちでメソッドの呼び出しのために rb_intern() で毎回シンボルを生成しているところを id.h の生成済みのシンボルを利用するようにするリファクタリングです。 [ruby-core:50472] [Bug #7495]

tarui:r38144 2012-12-02 19:28:27 +0900

r38142 で revert された r38141 の再修正です。 r38141 でマシンスタックの保存を rb_gc_save_machine_context() の中に入れたのとは反対に、rb_gc_save_machine_context() の定義を消してその内容を関数マクロ RB_GC_SAVE_MACHINE_CONTEXT() で直接展開されるようにしています。レジスタとスタックポインタの保存はマクロを呼び出すスコープのものを保存しないといけないそうです。1つ関数呼び出しが増えても効率別として不具合がおきるような問題にはならないような気がするのですが、なぜでしょうか。
[追記]っていうのは大きな勘違いで、スタックポインタだけ保存してたってマシンスタックの内容がレジスタの保存時と同じでないと意味がなく、関数から抜けるとその内容が残る保証がないという問題でした。tarui さんがコメントで詳しく解説してくださったのでそちらも参考に。[/追記]

*1:puts じゃなくて print で明示的に文字列に "\n" を含んでるのはわざとです。IO#puts の動作に詳しい人はピンとくるでしょうけど、puts にすると write 2回呼ばれるので少し結果が複雑になるので