Exemple #1
0
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);
}
Exemple #3
0
/*
 * 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;
}
Exemple #7
0
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);
}