void
rb_alias(VALUE klass, ID name, ID def)
{
    VALUE target_klass = klass;
    rb_method_entry_t *orig_me;
    rb_method_flag_t flag = NOEX_UNDEF;

    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "no class to make alias");
    }

    rb_frozen_class_p(klass);
    if (klass == rb_cObject) {
	rb_secure(4);
    }

  again:
    orig_me = search_method(klass, def);

    if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
	if ((!RB_TYPE_P(klass, T_MODULE)) ||
	    (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) {
	    rb_print_undef(klass, def, 0);
	}
    }
    if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
	klass = RCLASS_SUPER(klass);
	def = orig_me->def->original_id;
	flag = orig_me->flag;
	goto again;
    }

    if (flag == NOEX_UNDEF) flag = orig_me->flag;
    rb_method_entry_set(target_klass, name, orig_me, flag);
}
Exemple #2
0
static void
rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
{
    rb_method_entry_t *me;
    VALUE defined_class;

    me = search_method(klass, name, &defined_class);
    if (!me && RB_TYPE_P(klass, T_MODULE)) {
	me = search_method(rb_cObject, name, &defined_class);
    }

    if (UNDEFINED_METHOD_ENTRY_P(me) ||
	UNDEFINED_REFINED_METHOD_P(me->def)) {
	rb_print_undef(klass, name, 0);
    }

    if (me->flag != noex) {
	rb_vm_check_redefinition_opt_method(me, klass);

	if (klass == defined_class ||
	    RCLASS_ORIGIN(klass) == defined_class) {
	    me->flag = noex;
	    if (me->def->type == VM_METHOD_TYPE_REFINED) {
		me->def->body.orig_me->flag = noex;
	    }
	    rb_clear_method_cache_by_class(klass);
	}
	else {
	    rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
	}
    }
}
static void
rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
{
    rb_method_entry_t *me;

    if (klass == rb_cObject) {
	rb_secure(4);
    }

    me = search_method(klass, name);
    if (!me && RB_TYPE_P(klass, T_MODULE)) {
	me = search_method(rb_cObject, name);
    }

    if (UNDEFINED_METHOD_ENTRY_P(me)) {
	rb_print_undef(klass, name, 0);
    }

    if (me->flag != noex) {
	rb_vm_check_redefinition_opt_method(me, klass);

	if (klass == me->klass) {
	    me->flag = noex;
	}
	else {
	    rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
	}
    }
}
Exemple #4
0
/*
 * 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,
				  VALUE *defined_class_ptr)
{
    VALUE defined_class;
    rb_method_entry_t *me = search_method(klass, id, &defined_class);

    if (me && me->klass) {
	switch (BUILTIN_TYPE(me->klass)) {
	  case T_CLASS:
	    if (RBASIC(klass)->flags & FL_SINGLETON) break;
	    /* fall through */
	  case T_ICLASS:
	    defined_class = me->klass;
	}
    }

    if (ruby_running) {
	if (OPT_GLOBAL_METHOD_CACHE) {
	    struct cache_entry *ent;
	    ent = GLOBAL_METHOD_CACHE(klass, id);
	    ent->class_serial = RCLASS_SERIAL(klass);
	    ent->method_state = GET_GLOBAL_METHOD_STATE();
	    ent->defined_class = defined_class;
	    ent->mid = id;

	    if (UNDEFINED_METHOD_ENTRY_P(me)) {
		ent->me = 0;
		me = 0;
	    }
	    else {
		ent->me = me;
	    }
	}
	else if (UNDEFINED_METHOD_ENTRY_P(me)) {
	    me = 0;
	}
    }

    if (defined_class_ptr)
	*defined_class_ptr = defined_class;
    return me;
}
Exemple #5
0
static int add_method_if_undefined(ID method_name, rb_method_entry_t *me, VALUE *names) {
#ifdef ID_ALLOCATOR
  /* The allocator can be undefined with rb_undef_alloc_func, e.g. Struct. */
  if (method_name == ID_ALLOCATOR)
    return ST_CONTINUE;
#endif

  if (UNDEFINED_METHOD_ENTRY_P(me))
    rb_ary_push(*names, ID2SYM(method_name));
  return ST_CONTINUE;
}
void
rb_alias(VALUE klass, ID name, ID def)
{
    rb_method_entry_t *orig_me;

    rb_frozen_class_p(klass);
    if (klass == rb_cObject) {
	rb_secure(4);
    }

    orig_me = search_method(klass, def);

    if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
	if ((TYPE(klass) != T_MODULE) ||
	    (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) {
	    rb_print_undef(klass, def, 0);
	}
    }

    rb_add_method_me(klass, name, orig_me, orig_me->flag);
}
Exemple #7
0
static int add_method_if_matching(ID method_name, rb_method_entry_t *me, add_method_if_matching_arg_t *arg) {
  if (method_name == ID_ALLOCATOR)
    return ST_CONTINUE;

  if (UNDEFINED_METHOD_ENTRY_P(me))
    return ST_CONTINUE;

  if ((me->flag & NOEX_MASK) == arg->visibility)
    rb_ary_push(arg->names, ID2SYM(method_name));

  return ST_CONTINUE;
}
Exemple #8
0
void
rb_alias(VALUE klass, ID name, ID def)
{
    VALUE target_klass = klass;
    VALUE defined_class;
    rb_method_entry_t *orig_me;
    rb_method_flag_t flag = NOEX_UNDEF;

    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "no class to make alias");
    }

    rb_frozen_class_p(klass);

  again:
    orig_me = search_method(klass, def, &defined_class);

    if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
	UNDEFINED_REFINED_METHOD_P(orig_me->def)) {
	if ((!RB_TYPE_P(klass, T_MODULE)) ||
	    (orig_me = search_method(rb_cObject, def, 0),
	     UNDEFINED_METHOD_ENTRY_P(orig_me))) {
	    rb_print_undef(klass, def, 0);
	}
    }
    if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
	klass = RCLASS_SUPER(klass);
	def = orig_me->def->original_id;
	flag = orig_me->flag;
	goto again;
    }
    if (RB_TYPE_P(defined_class, T_ICLASS)) {
	VALUE real_class = RBASIC_CLASS(defined_class);
	if (real_class && RCLASS_ORIGIN(real_class) == defined_class)
	    defined_class = real_class;
    }

    if (flag == NOEX_UNDEF) flag = orig_me->flag;
    method_entry_set(target_klass, name, orig_me, flag, defined_class);
}
void
rb_undef(VALUE klass, ID id)
{
    rb_method_entry_t *me;

    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "no class to undef method");
    }
    if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
	rb_secure(4);
    }
    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
	rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
    }
    rb_frozen_class_p(klass);
    if (id == object_id || id == id__send__ || id == idInitialize) {
	rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
    }

    me = search_method(klass, id);

    if (UNDEFINED_METHOD_ENTRY_P(me)) {
	const char *s0 = " class";
	VALUE c = klass;

	if (FL_TEST(c, FL_SINGLETON)) {
	    VALUE obj = rb_ivar_get(klass, attached);

	    switch (TYPE(obj)) {
	      case T_MODULE:
	      case T_CLASS:
		c = obj;
		s0 = "";
	    }
	}
	else if (RB_TYPE_P(c, T_MODULE)) {
	    s0 = " module";
	}
	rb_name_error(id, "undefined method `%s' for%s `%s'",
		      rb_id2name(id), s0, rb_class2name(c));
    }

    rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);

    CALL_METHOD_HOOK(klass, undefined, id);
}
Exemple #10
0
static int
method_entry_i(st_data_t key, st_data_t value, st_data_t data)
{
    const rb_method_entry_t *me = (const rb_method_entry_t *)value;
    st_table *list = (st_table *)data;
    long type;

    if (!st_lookup(list, key, 0)) {
	if (UNDEFINED_METHOD_ENTRY_P(me)) {
	    type = -1; /* none */
	}
	else {
	    type = VISI(me->flag);
	}
	st_add_direct(list, key, type);
    }
    return ST_CONTINUE;
}
Exemple #11
0
rb_method_entry_t *
rb_method_entry_without_refinements(VALUE klass, ID id,
				    VALUE *defined_class_ptr)
{
    VALUE defined_class;
    rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);

    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
	me = rb_resolve_refined_method(Qnil, me, &defined_class);
    }
    if (defined_class_ptr)
	*defined_class_ptr = defined_class;
    if (UNDEFINED_METHOD_ENTRY_P(me)) {
	return 0;
    }
    else {
	return me;
    }
}
static VALUE
rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
{
    int i;
    ID id;
    const rb_method_entry_t *me;

    if (!RB_TYPE_P(module, T_MODULE)) {
	rb_raise(rb_eTypeError, "module_function must be called for modules");
    }

    secure_visibility(module);
    if (argc == 0) {
	SCOPE_SET(NOEX_MODFUNC);
	return module;
    }

    set_method_visibility(module, argc, argv, NOEX_PRIVATE);

    for (i = 0; i < argc; i++) {
	VALUE m = module;

	id = rb_to_id(argv[i]);
	for (;;) {
	    me = search_method(m, id);
	    if (me == 0) {
		me = search_method(rb_cObject, id);
	    }
	    if (UNDEFINED_METHOD_ENTRY_P(me)) {
		rb_print_undef(module, id, 0);
	    }
	    if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
		break; /* normal case: need not to follow 'super' link */
	    }
	    m = RCLASS_SUPER(m);
	    if (!m)
		break;
	}
	rb_method_entry_set(rb_singleton_class(module), id, me, NOEX_PUBLIC);
    }
    return module;
}
Exemple #13
0
static int
method_entry(ID key, const rb_method_entry_t *me, st_table *list)
{
    long type;

    if (key == ID_ALLOCATOR) {
	return ST_CONTINUE;
    }

    if (!st_lookup(list, key, 0)) {
	if (UNDEFINED_METHOD_ENTRY_P(me)) {
	    type = -1; /* none */
	}
	else {
	    type = VISI(me->flag);
	}
	st_add_direct(list, key, type);
    }
    return ST_CONTINUE;
}
Exemple #14
0
static int
method_entry_i(st_data_t key, st_data_t value, st_data_t data)
{
    const rb_method_entry_t *me = (const rb_method_entry_t *)value;
    st_table *list = (st_table *)data;
    long type;

    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
	me = rb_resolve_refined_method(Qnil, me, NULL);
	if (!me) return ST_CONTINUE;
    }
    if (!st_lookup(list, key, 0)) {
	if (UNDEFINED_METHOD_ENTRY_P(me)) {
	    type = -1; /* none */
	}
	else {
	    type = VISI(me->flag);
	}
	st_add_direct(list, key, type);
    }
    return ST_CONTINUE;
}
Exemple #15
0
void
rb_undef(VALUE klass, ID id)
{
    rb_method_entry_t *me;

    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "no class to undef method");
    }
    rb_frozen_class_p(klass);
    if (id == object_id || id == id__send__ || id == idInitialize) {
	rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
    }

    me = search_method(klass, id, 0);

    if (UNDEFINED_METHOD_ENTRY_P(me) ||
	UNDEFINED_REFINED_METHOD_P(me->def)) {
	const char *s0 = " class";
	VALUE c = klass;

	if (FL_TEST(c, FL_SINGLETON)) {
	    VALUE obj = rb_ivar_get(klass, attached);

	    if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) {
		c = obj;
		s0 = "";
	    }
	}
	else if (RB_TYPE_P(c, T_MODULE)) {
	    s0 = " module";
	}
	rb_name_error(id, "undefined method `%"PRIsVALUE"' for%s `%"PRIsVALUE"'",
		      QUOTE_ID(id), s0, rb_class_name(c));
    }

    rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);

    CALL_METHOD_HOOK(klass, undefined, 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 #18
0
static int add_method_if_undefined(ID method_name, rb_method_entry_t *me, VALUE *names) {
  if (UNDEFINED_METHOD_ENTRY_P(me))
    rb_ary_push(*names, ID2SYM(method_name));
  return ST_CONTINUE;
}