Railsプルリクのぞき見 - 2018/10/10
RubyやRailsにちょっとでも貢献したいんですが、まだまだ若輩者なのでRubyやRailsのプルリクなどを半年ROMっていようかと。
継続できるように、雑に眺めて内容がわかったものをピックアップして紹介してみる。
nilClassのtryを高速化
メソッドの引数定義を def try(*args) から def try(method_name = nil, *args) ってするだけで処理速度が上がるみたい。
nilClassだけなのはなんでかな?と思ったら、他のクラスは元々第一引数を method_name としてあったんですねー。nilClassはどうせnil返すだけで引数使わないからって*argsだけにしてたらRubyがメソッド呼び出すのに時間がかかってしまうようですね。
Rubyがメソッドの可変長引数を解釈しているところはどこだろう。そのコードまで追えるかな...
Rubyでの引数の扱い
↑の記事によると、Rubyには8種類の引数(パラメーター)がある。
Rubyの中では↓の構造体で表現しているもよう。
struct args_info { /* basic args info */ VALUE *argv; int argc; const struct rb_call_info_kw_arg *kw_arg; /* additional args info */ int rest_index; VALUE *kw_argv; VALUE rest; };
ruby/vm_args.c at ruby_2_5 · ruby/ruby · GitHub
たぶん、argv argc が必須な引数を表していて、kw_argvはキーワード引数だろうから、restがsplat部分かな。
同ファイルの setup_parameters_complex っていう関数でなんかごにょごにょしてるあたりかなー。
if (iseq->body->param.flags.has_opt) { int opt = args_setup_opt_parameters(args, iseq->body->param.opt_num, locals + iseq->body->param.lead_num); opt_pc = (int)iseq->body->param.opt_table[opt]; } if (iseq->body->param.flags.has_rest) { args_setup_rest_parameter(args, locals + iseq->body->param.rest_start); }
args_setup_rest_parameterの中でarg_copy関数使ってsplatパラメーターをコピーしたりしてるっぽい。
ということは、def try(*args)にたいして xxx.try(:hoge)と呼び出すと引数データのコピーとかが実行されるってことかな。
それを def try(:method_name = nil, *args) にするとargs_setup_opt_parametersの方が使われて、そのなかではコピーはしてせずにargv argcにセットしているもよう。
っていう感じで実行速度に差がでる... ってことでいいのかな?