static int include_modules_at(const VALUE klass, VALUE c, VALUE module) { VALUE p, iclass; int method_changed = 0, constant_changed = 0; const st_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass)); while (module) { int superclass_seen = FALSE; if (RCLASS_ORIGIN(module) != module) goto skip; if (klass_m_tbl && klass_m_tbl == RCLASS_M_TBL(module)) return -1; /* ignore if the module included already in superclasses */ for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) { switch (BUILTIN_TYPE(p)) { case T_ICLASS: if (RCLASS_M_TBL_WRAPPER(p) == RCLASS_M_TBL_WRAPPER(module)) { if (!superclass_seen) { c = p; /* move insertion point */ } goto skip; } break; case T_CLASS: superclass_seen = TRUE; break; } } iclass = rb_include_class_new(module, RCLASS_SUPER(c)); c = RCLASS_SET_SUPER(c, iclass); if (BUILTIN_TYPE(module) == T_ICLASS) { rb_module_add_to_subclasses_list(RBASIC(module)->klass, iclass); } else { rb_module_add_to_subclasses_list(module, iclass); } if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) { VALUE refined_class = rb_refinement_module_get_refined_class(klass); st_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i, (st_data_t) refined_class); FL_SET(c, RMODULE_INCLUDED_INTO_REFINEMENT); } if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) method_changed = 1; if (RMODULE_CONST_TBL(module) && RMODULE_CONST_TBL(module)->num_entries) constant_changed = 1; skip: module = RCLASS_SUPER(module); } if (method_changed) rb_clear_method_cache_by_class(klass); if (constant_changed) rb_clear_constant_cache(); return method_changed; }
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, VALUE defined_class) { rb_method_entry_t *me; #if NOEX_NOREDEF VALUE rklass; #endif st_table *mtbl; st_data_t data; int make_refined = 0; if (NIL_P(klass)) { klass = rb_cObject; } if (!FL_TEST(klass, FL_SINGLETON) && type != VM_METHOD_TYPE_NOTIMPLEMENTED && type != VM_METHOD_TYPE_ZSUPER) { switch (mid) { case idInitialize: case idInitialize_copy: case idInitialize_clone: case idInitialize_dup: case idRespond_to_missing: noex |= NOEX_PRIVATE; } } rb_frozen_class_p(klass); #if NOEX_NOREDEF rklass = klass; #endif if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) { VALUE refined_class = rb_refinement_module_get_refined_class(klass); rb_add_refined_method_entry(refined_class, mid); } if (type == VM_METHOD_TYPE_REFINED) { rb_method_entry_t *old_me = lookup_method_table(RCLASS_ORIGIN(klass), mid); if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass); } else { klass = RCLASS_ORIGIN(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; #if NOEX_NOREDEF if (old_me->flag & NOEX_NOREDEF) { rb_raise(rb_eTypeError, "cannot redefine %"PRIsVALUE"#%"PRIsVALUE, rb_class_name(rklass), rb_id2str(mid)); } #endif rb_vm_check_redefinition_opt_method(old_me, klass); if (old_def->type == VM_METHOD_TYPE_REFINED) make_refined = 1; 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 %"PRIsVALUE, rb_id2str(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->location.path)) { int line = iseq->line_info_table ? FIX2INT(rb_iseq_first_lineno(iseq->self)) : 0; rb_compile_warning(RSTRING_PTR(iseq->location.path), line, "previous definition of %"PRIsVALUE" was here", rb_id2str(old_def->original_id)); } } rb_unlink_method_entry(old_me); } me = ALLOC(rb_method_entry_t); rb_clear_method_cache_by_class(klass); me->flag = NOEX_WITH_SAFE(noex); me->mark = 0; me->called_id = mid; RB_OBJ_WRITE(klass, &me->klass, defined_class); me->def = def; if (def) { def->alias_count++; switch(def->type) { case VM_METHOD_TYPE_ISEQ: RB_OBJ_WRITTEN(klass, Qundef, def->body.iseq->self); break; case VM_METHOD_TYPE_IVAR: RB_OBJ_WRITTEN(klass, Qundef, def->body.attr.location); break; case VM_METHOD_TYPE_BMETHOD: RB_OBJ_WRITTEN(klass, Qundef, def->body.proc); break; default:; /* ignore */ } } /* 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 && search_method(klass, mid, 0)) { rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid)); } } if (make_refined) { make_method_entry_refined(me); } st_insert(mtbl, mid, (st_data_t) me); return me; }