Rubyのメソッド呼び出しの流れ(2)
前回からの続き、rb_call_cache構造体を見ていきます。 コードの後に説明書くと分かりにくかったので、行ごとにある程度コメントを書いてみます。
rb_call_cacheはvm_core.hにあります。
237struct rb_call_cache; 238typedef VALUE (*vm_call_handler)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc); 239 240struct rb_call_cache { 241 /* inline cache: keys */ // rubyのインラインメソッドキャッシュに渡すKVを表現してると思われる 242 rb_serial_t method_state; 243 rb_serial_t class_serial; 244 245 /* inline cache: values */ 246 const rb_callable_method_entry_t *me; // この構造体のメタ情報を持つテーブルへのポインタ 247 248 vm_call_handler call; // 目的のselect!のhandler。rb_ary_select_bangへの関数ポインタが格納されるはず 249 250 union { // メタ情報っぽい 251 unsigned int index; /* used by ivar */ 252 enum method_missing_reason method_missing_reason; /* used by method_missing */ 253 int inc_sp; /* used by cfunc */ 254 } aux; 255};
238 typedef
でvm_call_handler~~をVALUE型の別名として定義してます。
そして248 vm_call_handler call;
でメンバcallとして定義。
cm_call_handlerの引数でrb_call_cacheを渡しているので、rb_call_cacheを2回定義しているように見えますが、
これは自己参照ですかね?こういう書き方もあるんですね_〆(´ρ`⊂⌒`っ
さて、rb_call_cache.callについて見ていたらvm_call_andler型だったというところまでわかりました。
では、次にcallにrb_ary_select_bang
の関数ポインタを渡しているのは結局誰なんでしょうか。
send関数に戻り辿ってみたところ、vm_insnhelper.cのvm_search_methodにそれらしい記述がありました。 ここは前回も見た処理ですが再度スニペットを張ります。
1218vm_search_method(const struct rb_call_info *ci, struct rb_call_cache *cc, VALUE recv) 1219{ 1220 VALUE klass = CLASS_OF(recv); 1221 1222#if OPT_INLINE_METHOD_CACHE // インラインメソッドキャッシュヒットした時の処理 1223 if (LIKELY(GET_GLOBAL_METHOD_STATE() == cc->method_state && RCLASS_SERIAL(klass) == cc->class_serial)) { 1224 /* cache hit! */ 1225 VM_ASSERT(cc->call != NULL); 1226 return; 1227 } 1228#endif 1229 1230 cc->me = rb_callable_method_entry(klass, ci->mid); 1231 VM_ASSERT(callable_method_entry_p(cc->me)); 1232 cc->call = vm_call_general; // ★ここでrb_call_cache.callに代入されている 1233#if OPT_INLINE_METHOD_CACHE 1234 cc->method_state = GET_GLOBAL_METHOD_STATE(); 1235 cc->class_serial = RCLASS_SERIAL(klass); 1236#endif 1237}
どうやらvm_call_generalにrb_ary_select_bang
の関数ポインタが入っていそうです。
vm_call_generalを追います。
同じくvm_insnhelper.cに書かれています。
2305static VALUE 2306vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc) 2307{ 2308 return vm_call_method(th, reg_cfp, calling, ci, cc); // 実装はvm_call_method 2309} /* vm_call_methodを追う */ 2257static inline VALUE 2258vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc) 2259{ 2260 VM_ASSERT(callable_method_entry_p(cc->me)); 2261 2262 if (cc->me != NULL) { // rb_call_cacheで定義されていたコールバックがnullでなければ 2263 switch (METHOD_ENTRY_VISI(cc->me)) { // どうやら可視性を判断できるマクロ。cc->meは何ビット目だかに可視性を持っているみたい 2264 case METHOD_VISI_PUBLIC: /* likely */ // publicなメソッド 2265 return vm_call_method_each_type(th, cfp, calling, ci, cc); // 実体はこれ 2266 2267 case METHOD_VISI_PRIVATE: // privateメソッド /* snip */ 2278 case METHOD_VISI_PROTECTED: // protectedメソッド? /* snip */ 2296 default: 2297 rb_bug("unreachable"); 2298 } 2299 } 2300 else { 2301 return vm_call_method_nome(th, cfp, calling, ci, cc); // これがあのNoMethodErrorっぽい 2302 } 2303}
可視性はpublicと思われるので、気にせず vm_call_method_each_typeをみていきます。
2134static VALUE 2135vm_call_method_each_type(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc) 2136{ 2137 switch (cc->me->def->type) { // メソッドのタイプが設定されているようだ。 2138 case VM_METHOD_TYPE_ISEQ: /* 処理 */ 2142 case VM_METHOD_TYPE_NOTIMPLEMENTED: 2143 case VM_METHOD_TYPE_CFUNC: /* 処理 */ 2147 case VM_METHOD_TYPE_ATTRSET: /* 処理 */ 2154 case VM_METHOD_TYPE_IVAR: /* 処理 */ 2161 case VM_METHOD_TYPE_MISSING: /* 処理 */ 2166 case VM_METHOD_TYPE_BMETHOD: /* 処理 */ 2170 case VM_METHOD_TYPE_ALIAS: /* 処理 */ 2175 case VM_METHOD_TYPE_OPTIMIZED: /* 処理 */ 2188 case VM_METHOD_TYPE_UNDEF: /* 処理 */ 2191 case VM_METHOD_TYPE_ZSUPER: /* 処理 */ 2194 case VM_METHOD_TYPE_REFINED: { /* 処理 */ 2237}
メソッドのtypeらしきVM_METHOD_TYPE_xx
というもので、処理が分かれています。
メソッドのtypeってなんだろう(´・ω・` )?
method.hにrb_method_type_tというenumで定義されているようですが・・。
続きは次回にします!
スポンサードリンク
Rubyのしくみ -Ruby Under a Microscope-
- 作者: Pat Shaughnessy,島田浩二,角谷信太郎
- 出版社/メーカー: オーム社
- 発売日: 2014/11/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る