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); }
static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) { VALUE method; NODE *body; struct METHOD *data; VALUE rclass = klass; ID oid = id; again: if ((body = rb_get_method_body(klass, id, 0)) == 0) { rb_print_undef(rclass, oid, 0); } if (scope && (body->nd_noex & NOEX_MASK) != NOEX_PUBLIC) { rb_print_undef(rclass, oid, (body->nd_noex & NOEX_MASK)); } klass = body->nd_clss; body = body->nd_body; if (nd_type(body) == NODE_ZSUPER) { klass = RCLASS_SUPER(klass); goto again; } while (rclass != klass && (RCLASS_SINGLETON(rclass) || TYPE(rclass) == T_ICLASS)) { rclass = RCLASS_SUPER(rclass); } if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; method = Data_Make_Struct(mclass, struct METHOD, bm_mark, -1, data); data->oclass = klass; GC_WB(&data->recv, obj); data->id = id; data->body = body; data->rclass = rclass; data->oid = oid; #if !WITH_OBJC OBJ_INFECT(method, klass); #endif return method; }
static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mklass) { VALUE method; NODE *body; struct METHOD *data; VALUE rklass = klass; ID oid = id; again: if ((body = rb_get_method_body(klass, id, 0)) == 0) { print_undef(rklass, oid); } klass = body->nd_clss; body = body->nd_body; if (nd_type(body) == NODE_ZSUPER) { klass = RCLASS(klass)->super; goto again; } while (rklass != klass && (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) { rklass = RCLASS(rklass)->super; } if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; method = Data_Make_Struct(mklass, struct METHOD, bm_mark, -1, data); data->klass = klass; data->recv = obj; data->id = id; data->body = body; data->rklass = rklass; data->oid = oid; OBJ_INFECT(method, klass); return method; }
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); }