From: Shugo Maeda Date: 2012-11-12T18:20:21+09:00 Subject: [ruby-dev:46495] Re: Fwd: [ruby-changes:25559] shugo:r37616 (trunk): * vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo): 前田です。 2012年11月12日 17:10 SASADA Koichi : >  個人的には,「マイクロベンチマーク以外には効かないんだからいいよ」とい > う意見もありだろうと思うので,機能か性能か,の決定はどなたかにお任せした > いところです. > > >  どちらかというと,個人的な印象の話になってしまうのですが,性能よりも, > 「メソッド探索の根幹に関わる部分にようわからん処理で埋まる」というの > は,Ruby という言語をどんどん理解しがたいものにするので反対したい,とい > うのがあります.理解しがたい言語や機能は誤解されたり不幸にしかならない感じ. 了解しました。 まだ間に合うのでもっと反対意見も出していただければと思います。 >>>> * refineした時にrefine対象クラスにメソッドがない時はどうするか >>>> メソッドがない時も常にrefineされたことを示すmethod entryを追加する? >>> >>>  その点,私もあのあと気づいたのですが,refine されるメソッドは追加する >>> と良いと思います. >> >> 追加しない場合、メソッド探索失敗時もrefinementsの探索パスを通すことに >> なるかなと思いますが、後でrefine対象のクラスにメソッドが追加されたりすると >> まずそうなので、やっぱりrefineした時点でメソッドを追加しておかないと >> まずそうです。 > >  その場合のコストは現状と変わらないですよね.現状でも,必ず refinement > を気にするので. はい、実行コストは問題ないと思います。 実装コストも常にメソッドを追加した方が楽かな。 >> vm_call_methodに分岐を増やして、 >> >> case VM_METHOD_TYPE_REFINED:{ >> rb_call_info_t cie = *ci; >> ci = &cie; >> >> ci->me = (refinementsから探索したmethod entry、または元のクラスのmethod entry); >> if (ci->me != 0) { >> goto normal_method_dispatch; >> } >> else { >> /* refinementsからメソッドが見つからず、元のクラスにもメソッド定義がない場合 */ >> goto start_method_dispatch; >> } >> >> とするようなイメージで合っていますか? > >  はい.ちなみに,rb_call_info_t を引き回す設計には問題があることがわ > かっている(メソッド呼び出し途中で to_proc や to_a を読んだとき,破壊さ > れる可能性がある)ため,今代替案を検討中です. 了解しました。 >  else 節のほうは,super class を探索しないといけないので,ちょっと違う > ような気がしますが,「または元のクラスのmethod entry」が super class 探 > 索を含意している気もしますね. ああ、そうですね。考慮漏れでした。 >> refinementsから探索したmethod entryは通常のインラインキャッシュには >> 載らないのですよね? >> # できれば別のところにキャッシュを置いた方がいいかもしれないですけど。 > >  yes.インラインキャッシュには乗りません.なので,色々シンプルになると > 思います. > >  性能で問題になるようなら,refinement 用の global cache を用意すれば良 > いかと思います. はい。 >>>  結論が出たら,私が実装しますかね. >> >> 意図を正しく理解できているか不安ではありますが、ささださんは他にも作業が >> たくさんありそうなので、いったん私がやってみましょうか? > >  もし,お時間がありそうであれば(前田さんもお忙しいと思いますが...). > あと,上述したとおり,rb_call_info_t を引き回す設計を改造する予定なの > で,その作業後から取りかかった方がいいかもしれません.少なくとも,今週中 > には直します. 了解です。では来週やってみます。 あと、別のメールでprependよりrefinementを優先してほしいとまつもとさんが おっしゃっているので、その方法を考えないといけないですね。 一貫性を考えるとprependの方が優先されてもいい気がしますが、使い勝手は refinement優先の方がよいように思います。 ちょっと考えたのですが、すでにモジュールがprependされているクラスをrefine した場合は、prependされているモジュールにrefinedメソッドを追加してしまうの がよいように思います。 そうすると、同じモジュールをprependしている他のクラスのメソッド探索にも 影響がありますが、速度低下だけで動作自体は同じになると考えています。 問題は、refineされた後でprependされた場合ですが、こちらはちょっと対応が 面倒そうですねえ。 prependした時に、常にprepend対象のクラスのメソッドテーブルを調べて、 モジュールにrefinedメソッドを追加するくらいですかねえ。 >> あと、本題と関係ありませんが、コードを読んでいて以下の疑問がありました。 >> >> * rb_iseq_t::ic_entriesはまだ使われていますか? > >  はい.ic_entry はインラインキャッシュ用であり,インラインメソッド > キャッシュ(IMC)専用のものではありません. > >  以前は IMC もこれで使っていましたが,他にもインスタンス変数のインデッ > クスのキャッシュ,定数キャッシュなどで利用しています. ああ、なるほど、了解しました。 >> * callinfoとcall_infoで名前の付け方に揺れがあるのは意図的ですか? > >  これ迷ったんですよねぇ.rb_callinfo_t に抵抗があったんです > が,prefix/suffix 的に使う場合に call_info ってのには変だと思い. なるほど。 >  全部 callinfo に付け替えようかなぁ. 統一した方がよい気がしますね。 -- Shugo Maeda