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); } } }
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 }
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); } } }
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; }
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; }
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)); } }
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); } } }
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; }
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; }
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); }
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); }