devひよこのあしあと

いつでもひよっこな気持ちで学びと挑戦を

Railsプルリクのぞき見 - 2018/10/10

RubyRailsにちょっとでも貢献したいんですが、まだまだ若輩者なのでRubyRailsのプルリクなどを半年ROMっていようかと。

継続できるように、雑に眺めて内容がわかったものをピックアップして紹介してみる。

nilClassのtryを高速化

github.com

メソッドの引数定義を def try(*args) から def try(method_name = nil, *args) ってするだけで処理速度が上がるみたい。

nilClassだけなのはなんでかな?と思ったら、他のクラスは元々第一引数を method_name としてあったんですねー。nilClassはどうせnil返すだけで引数使わないからって*argsだけにしてたらRubyがメソッド呼び出すのに時間がかかってしまうようですね。

Rubyがメソッドの可変長引数を解釈しているところはどこだろう。そのコードまで追えるかな...

Rubyでの引数の扱い

techracho.bpsinc.jp

↑の記事によると、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にセットしているもよう。

っていう感じで実行速度に差がでる... ってことでいいのかな?