NODE * rb_method_node(VALUE klass, ID id) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); if (ent->mid == id && ent->klass == klass && ent->method) { return ent->method; } return rb_get_method_body(klass, id, 0); }
rb_method_entry_t * rb_method_entry(VALUE klass, ID id) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); if (ent->mid == id && ent->klass == klass) { return ent->me; } return rb_get_method_entry(klass, id); }
/* * search method body (NODE_METHOD) * with : klass and id * without : method cache * * if you need method node with method cache, use * rb_method_node() */ NODE * rb_get_method_body(VALUE klass, ID id, ID *idp) { NODE *volatile fbody, *body; NODE *method; if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) { /* store empty info in cache */ struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->klass = klass; ent->mid = ent->mid0 = id; ent->method = 0; ent->oklass = 0; return 0; } method = fbody->nd_body; if (ruby_running) { /* store in cache */ struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->klass = klass; ent->mid = id; ent->mid0 = fbody->nd_oid; ent->method = body = method; ent->oklass = method->nd_clss; } else { body = method; } if (idp) { *idp = fbody->nd_oid; } return body; }
rb_method_entry_t * rb_method_entry(VALUE klass, ID id) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); if (ent->filled_version == GET_VM_STATE_VERSION() && ent->mid == id && ent->klass == klass) { return ent->me; } return rb_method_entry_get_without_cache(klass, id); }
/* * search method entry without method cache. * * if you need method entry with method cache, use * rb_method_entry() */ rb_method_entry_t * rb_get_method_entry(VALUE klass, ID id) { rb_method_entry_t *me = search_method(klass, id); if (ruby_running) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->klass = klass; if (UNDEFINED_METHOD_ENTRY_P(me)) { ent->mid = id; ent->me = 0; me = 0; } else { ent->mid = id; ent->me = me; } } return me; }
/* * search method entry without the method cache. * * if you need method entry with method cache (normal case), use * rb_method_entry() simply. */ rb_method_entry_t * rb_method_entry_get_without_cache(VALUE klass, ID id) { rb_method_entry_t *me = search_method(klass, id); if (ruby_running) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->filled_version = GET_VM_STATE_VERSION(); ent->klass = klass; if (UNDEFINED_METHOD_ENTRY_P(me)) { ent->mid = id; ent->me = 0; me = 0; } else { ent->mid = id; ent->me = me; } } return me; }
static inline VALUE rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope, VALUE self) { NODE *body, *method; int noex; ID id = mid; struct cache_entry *ent; rb_thread_t *th = GET_THREAD(); if (!klass) { rb_raise(rb_eNotImpError, "method `%s' called on terminated object (%p)", rb_id2name(mid), (void *)recv); } /* is it in the method cache? */ ent = cache + EXPR1(klass, mid); if (ent->mid == mid && ent->klass == klass) { if (!ent->method) return method_missing(recv, mid, argc, argv, scope == 2 ? NOEX_VCALL : 0); id = ent->mid0; noex = ent->method->nd_noex; klass = ent->method->nd_clss; body = ent->method->nd_body; } else if ((method = rb_get_method_body(klass, id, &id)) != 0) { noex = method->nd_noex; klass = method->nd_clss; body = method->nd_body; } else { if (scope == 3) { return method_missing(recv, mid, argc, argv, NOEX_SUPER); } return method_missing(recv, mid, argc, argv, scope == 2 ? NOEX_VCALL : 0); } if (mid != idMethodMissing) { /* receiver specified form for private method */ if (UNLIKELY(noex)) { if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == 0) { return method_missing(recv, mid, argc, argv, NOEX_PRIVATE); } /* self must be kind of a specified form for protected method */ if (((noex & NOEX_MASK) & NOEX_PROTECTED) && scope == 0) { VALUE defined_class = klass; if (TYPE(defined_class) == T_ICLASS) { defined_class = RBASIC(defined_class)->klass; } if (self == Qundef) { self = th->cfp->self; } if (!rb_obj_is_kind_of(self, rb_class_real(defined_class))) { return method_missing(recv, mid, argc, argv, NOEX_PROTECTED); } } if (NOEX_SAFE(noex) > th->safe_level) { rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(mid)); } } } stack_check(); return vm_call0(th, klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER); }