Пример #1
0
static void
rb_export_method(VALUE klass, ID name, ID noex)
{
    NODE *fbody;
    VALUE origin;

    if (klass == rb_cObject) {
	rb_secure(4);
    }
    fbody = search_method(klass, name, &origin);
    if (!fbody && TYPE(klass) == T_MODULE) {
	fbody = search_method(rb_cObject, name, &origin);
    }
    if (!fbody || !fbody->nd_body) {
	rb_print_undef(klass, name, 0);
    }
    if (fbody->nd_body->nd_noex != noex) {
	if (nd_type(fbody->nd_body->nd_body) == NODE_CFUNC) {
	    rb_vm_check_redefinition_opt_method(fbody);
	}
	if (klass == origin) {
	    fbody->nd_body->nd_noex = noex;
	}
	else {
	    rb_add_method(klass, name, NEW_ZSUPER(), noex);
	}
    }
}
Пример #2
0
static void
rb_export_method(VALUE klass, ID name, ID noex)
{
    rb_vm_method_node_t *node;
    SEL sel;

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

    if (!rb_vm_lookup_method2((Class)klass, name, &sel, NULL, &node)) {
	if (TYPE(klass) != T_MODULE
	    || !rb_vm_lookup_method2((Class)rb_cObject, name, &sel, NULL, &node)) {
	    rb_print_undef(klass, name, 0);
	}
    }

#if 0 // TODO
    if (node->nd_noex != noex) {
	// TODO if the method exists on a super class, we should add a new method
	// with the correct noex that calls super
	assert(!rb_vm_lookup_method((Class)RCLASS_SUPER(klass), sel, NULL, NULL));

	node->nd_noex = noex;
    }
#endif
}
Пример #3
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);
	}
    }
}
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);
}
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);
	}
    }
}
Пример #6
0
rb_vm_method_t *
rb_vm_get_method(VALUE klass, VALUE obj, ID mid, int scope)
{
    SEL sel = 0;
    IMP imp = NULL;
    rb_vm_method_node_t *node = NULL;

    // TODO honor scope

    if (!rb_vm_lookup_method2((Class)klass, mid, &sel, &imp, &node)) {
	rb_print_undef(klass, mid, 0);
    }

    Class k, oklass = (Class)klass;
    while ((k = class_getSuperclass(oklass)) != NULL) {
	if (!rb_vm_lookup_method(k, sel, NULL, NULL)) {
	    break;
	}
	oklass = k;
    }

    Method method = class_getInstanceMethod((Class)klass, sel);
    assert(method != NULL);

    int arity;
    rb_vm_method_node_t *new_node;
    if (node == NULL) {
	arity = rb_method_getNumberOfArguments(method) - 2;
	new_node = NULL;
    }
    else {
	arity = rb_vm_arity_n(node->arity);
	new_node = (rb_vm_method_node_t *)xmalloc(sizeof(rb_vm_method_node_t));
	memcpy(new_node, node, sizeof(rb_vm_method_node_t));
    }

    rb_vm_method_t *m = (rb_vm_method_t *)xmalloc(sizeof(rb_vm_method_t));

    m->oclass = (VALUE)oklass;
    m->rclass = klass;
    GC_WB(&m->recv, obj);
    m->sel = sel;
    m->arity = arity;
    GC_WB(&m->node, new_node);

    // Let's allocate a static cache here, since a rb_vm_method_t must always
    // point to the method it was created from.
    struct mcache *c = (struct mcache *)xmalloc(sizeof(struct mcache));
    if (new_node == NULL) {
	fill_ocache(c, obj, oklass, imp, sel, method, arity);
    }
    else {
	fill_rcache(c, oklass, sel, new_node);
    }
    GC_WB(&m->cache, c);

    return m;
}
Пример #7
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;
}
Пример #8
0
void
rb_alias(VALUE klass, ID name, ID def)
{
    NODE *orig_fbody, *node, *method;
    VALUE singleton = 0;
    st_data_t data;

    rb_frozen_class_p(klass);
    if (klass == rb_cObject) {
	rb_secure(4);
    }
    orig_fbody = search_method(klass, def, 0);
    if (!orig_fbody || !orig_fbody->nd_body) {
	if (TYPE(klass) == T_MODULE) {
	    orig_fbody = search_method(rb_cObject, def, 0);
	}
    }
    if (!orig_fbody || !orig_fbody->nd_body) {
	rb_print_undef(klass, def, 0);
    }
    if (FL_TEST(klass, FL_SINGLETON)) {
	singleton = rb_iv_get(klass, "__attached__");
    }

    orig_fbody->nd_cnt++;

    if (st_lookup(RCLASS_M_TBL(klass), name, &data)) {
	node = (NODE *)data;
	if (node) {
	    if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) {
		rb_warning("discarding old %s", rb_id2name(name));
	    }
	    if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
		rb_vm_check_redefinition_opt_method(node);
	    }
	}
    }

    st_insert(RCLASS_M_TBL(klass), name,
	      (st_data_t) NEW_FBODY(
		  method = NEW_METHOD(orig_fbody->nd_body->nd_body,
			     orig_fbody->nd_body->nd_clss,
			     NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), def));
    method->nd_file = (void *)def;

    rb_clear_cache_by_id(name);

    if (!ruby_running) return;

    if (singleton) {
	rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
    }
    else {
	rb_funcall(klass, added, 1, ID2SYM(name));
    }
}
Пример #9
0
static void
rb_export_method(VALUE klass, ID name, ID noex)
{
    rb_vm_method_node_t *node;
    SEL sel;

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

    if (!rb_vm_lookup_method2((Class)klass, name, &sel, NULL, &node)) {
	if (TYPE(klass) != T_MODULE
		|| !rb_vm_lookup_method2((Class)rb_cObject, name, &sel, NULL,
		    &node)) {
	    rb_print_undef(klass, name, 0);
	}
    }

    if (node == NULL) {
	rb_raise(rb_eRuntimeError,
		"can't change visibility of non Ruby method `%s'",
		sel_getName(sel));
    }

    long flags = (node->flags & ~VM_METHOD_PRIVATE) & ~VM_METHOD_PROTECTED;
    switch (noex) {
	case NOEX_PRIVATE:
	    flags |= VM_METHOD_PRIVATE;
	    break;

	case NOEX_PROTECTED:
	    flags |= VM_METHOD_PROTECTED;
	    break;

	default:
	    break;
    }

    if (node->flags != flags) {
	if (node->klass == (Class)klass) {
	    node->flags = flags;
	}
	else {
	    rb_vm_define_method2((Class)klass, sel, node, flags, false);
	}
    }
}
Пример #10
0
static VALUE
rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
{
    int i;
    ID id;
    NODE *fbody;

    if (TYPE(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 (;;) {
	    fbody = search_method(m, id, &m);
	    if (fbody == 0) {
		fbody = search_method(rb_cObject, id, &m);
	    }
	    if (fbody == 0 || fbody->nd_body == 0) {
		rb_print_undef(module, id, 0);
	    }
	    if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) {
		break;		/* normal case: need not to follow 'super' link */
	    }
	    m = RCLASS_SUPER(m);
	    if (!m)
		break;
	}
	rb_add_method(rb_singleton_class(module), id, fbody->nd_body->nd_body,
		      NOEX_PUBLIC);
    }
    return module;
}
Пример #11
0
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;
}
Пример #12
0
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);
}
Пример #13
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);
}