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)); } }
void rb_add_method(VALUE klass, ID mid, NODE * node, int noex) { NODE *body; if (NIL_P(klass)) { klass = rb_cObject; } if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) { rb_raise(rb_eSecurityError, "Insecure: can't define method"); } if (!FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) != NODE_ZSUPER && (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) { noex = NOEX_PRIVATE | noex; } else if (FL_TEST(klass, FL_SINGLETON) && node && nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) { rb_warn ("defining %s.allocate is deprecated; use rb_define_alloc_func()", rb_class2name(rb_iv_get(klass, "__attached__"))); mid = ID_ALLOCATOR; } if (OBJ_FROZEN(klass)) { rb_error_frozen("class/module"); } rb_clear_cache_by_id(mid); /* * NODE_METHOD (NEW_METHOD(body, klass, vis)): * nd_body : method body // (2) // mark * nd_clss : klass // (1) // mark * nd_noex : visibility // (3) * * NODE_FBODY (NEW_FBODY(method, alias)): * nd_body : method (NODE_METHOD) // (2) // mark * nd_oid : original id // (1) * nd_cnt : alias count // (3) */ if (node) { body = NEW_FBODY(NEW_METHOD(node, klass, NOEX_WITH_SAFE(noex)), 0); } else { body = 0; } { /* check re-definition */ st_data_t data; NODE *old_node; if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) { old_node = (NODE *)data; if (old_node) { if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(old_node); } if (RTEST(ruby_verbose) && node && old_node->nd_cnt == 0 && old_node->nd_body) { rb_warning("method redefined; discarding old %s", rb_id2name(mid)); } } } if (klass == rb_cObject && node && mid == idInitialize) { rb_warn("redefining Object#initialize may cause infinite loop"); } if (mid == object_id || mid == __send__) { if (node && nd_type(node) == RUBY_VM_METHOD_NODE) { rb_warn("redefining `%s' may cause serious problem", rb_id2name(mid)); } } } st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body); if (node && mid != ID_ALLOCATOR && ruby_running) { if (FL_TEST(klass, FL_SINGLETON)) { rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid)); } else { rb_funcall(klass, added, 1, ID2SYM(mid)); } } }
static rb_method_entry_t * rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type, rb_method_definition_t *def, rb_method_flag_t noex) { rb_method_entry_t *me; st_table *mtbl; st_data_t data; if (NIL_P(klass)) { klass = rb_cObject; } if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_UNTRUSTED(klass))) { rb_raise(rb_eSecurityError, "Insecure: can't define method"); } if (!FL_TEST(klass, FL_SINGLETON) && type != VM_METHOD_TYPE_NOTIMPLEMENTED && type != VM_METHOD_TYPE_ZSUPER && (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) { noex = NOEX_PRIVATE | noex; } else if (FL_TEST(klass, FL_SINGLETON) && type == VM_METHOD_TYPE_CFUNC && mid == rb_intern("allocate")) { rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()", rb_class2name(rb_ivar_get(klass, attached))); mid = ID_ALLOCATOR; } rb_check_frozen(klass); mtbl = RCLASS_M_TBL(klass); /* check re-definition */ if (st_lookup(mtbl, mid, &data)) { rb_method_entry_t *old_me = (rb_method_entry_t *)data; rb_method_definition_t *old_def = old_me->def; if (rb_method_definition_eq(old_def, def)) return old_me; rb_vm_check_redefinition_opt_method(old_me, klass); if (RTEST(ruby_verbose) && type != VM_METHOD_TYPE_UNDEF && old_def->alias_count == 0 && old_def->type != VM_METHOD_TYPE_UNDEF && old_def->type != VM_METHOD_TYPE_ZSUPER) { rb_iseq_t *iseq = 0; rb_warning("method redefined; discarding old %s", rb_id2name(mid)); switch (old_def->type) { case VM_METHOD_TYPE_ISEQ: iseq = old_def->body.iseq; break; case VM_METHOD_TYPE_BMETHOD: iseq = rb_proc_get_iseq(old_def->body.proc, 0); break; default: break; } if (iseq && !NIL_P(iseq->filename)) { int line = iseq->line_info_table ? rb_iseq_first_lineno(iseq) : 0; rb_compile_warning(RSTRING_PTR(iseq->filename), line, "previous definition of %s was here", rb_id2name(old_def->original_id)); } } rb_unlink_method_entry(old_me); } me = ALLOC(rb_method_entry_t); rb_clear_cache_by_id(mid); me->flag = NOEX_WITH_SAFE(noex); me->mark = 0; me->called_id = mid; me->klass = klass; me->def = def; if (def) def->alias_count++; /* check mid */ if (klass == rb_cObject && mid == idInitialize) { rb_warn("redefining Object#initialize may cause infinite loop"); } /* check mid */ if (mid == object_id || mid == id__send__) { if (type == VM_METHOD_TYPE_ISEQ) { rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid)); } } st_insert(mtbl, mid, (st_data_t) me); return me; }