Ruby  2.0.0p594(2014-10-27revision48167)
vm_method.c
Go to the documentation of this file.
00001 /*
00002  * This file is included by vm.c
00003  */
00004 
00005 #define CACHE_SIZE 0x800
00006 #define CACHE_MASK 0x7ff
00007 #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
00008 
00009 #define NOEX_NOREDEF 0
00010 #ifndef NOEX_NOREDEF
00011 #define NOEX_NOREDEF NOEX_RESPONDS
00012 #endif
00013 
00014 static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass);
00015 
00016 static ID object_id;
00017 static ID removed, singleton_removed, undefined, singleton_undefined;
00018 static ID added, singleton_added, attached;
00019 
00020 struct cache_entry {            /* method hash table. */
00021     VALUE filled_version;        /* filled state version */
00022     ID mid;                     /* method's id */
00023     VALUE klass;                /* receiver's class */
00024     rb_method_entry_t *me;
00025     VALUE defined_class;
00026 };
00027 
00028 static struct cache_entry cache[CACHE_SIZE];
00029 #define ruby_running (GET_VM()->running)
00030 /* int ruby_running = 0; */
00031 
00032 static void
00033 vm_clear_global_method_cache(void)
00034 {
00035     struct cache_entry *ent, *end;
00036 
00037     ent = cache;
00038     end = ent + CACHE_SIZE;
00039     while (ent < end) {
00040         ent->filled_version = 0;
00041         ent++;
00042     }
00043 }
00044 
00045 void
00046 rb_clear_cache(void)
00047 {
00048     rb_vm_change_state();
00049 }
00050 
00051 static void
00052 rb_clear_cache_for_undef(VALUE klass, ID id)
00053 {
00054     rb_vm_change_state();
00055 }
00056 
00057 static void
00058 rb_clear_cache_by_id(ID id)
00059 {
00060     rb_vm_change_state();
00061 }
00062 
00063 void
00064 rb_clear_cache_by_class(VALUE klass)
00065 {
00066     rb_vm_change_state();
00067 }
00068 
00069 VALUE
00070 rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
00071 {
00072     rb_notimplement();
00073 
00074     UNREACHABLE;
00075 }
00076 
00077 static void
00078 rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex)
00079 {
00080     rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex);
00081 }
00082 
00083 void
00084 rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex)
00085 {
00086     if (argc < -2 || 15 < argc) rb_raise(rb_eArgError, "arity out of range: %d for -2..15", argc);
00087     if (func != rb_f_notimplement) {
00088         rb_method_cfunc_t opt;
00089         opt.func = func;
00090         opt.argc = argc;
00091         rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, noex);
00092     }
00093     else {
00094         rb_define_notimplement_method_id(klass, mid, noex);
00095     }
00096 }
00097 
00098 void
00099 rb_unlink_method_entry(rb_method_entry_t *me)
00100 {
00101     struct unlinked_method_entry_list_entry *ume = ALLOC(struct unlinked_method_entry_list_entry);
00102     ume->me = me;
00103     ume->next = GET_VM()->unlinked_method_entry_list;
00104     GET_VM()->unlinked_method_entry_list = ume;
00105 }
00106 
00107 void
00108 rb_gc_mark_unlinked_live_method_entries(void *pvm)
00109 {
00110     rb_vm_t *vm = pvm;
00111     struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list;
00112 
00113     while (ume) {
00114         if (ume->me->mark) {
00115             rb_mark_method_entry(ume->me);
00116         }
00117         ume = ume->next;
00118     }
00119 }
00120 
00121 void
00122 rb_sweep_method_entry(void *pvm)
00123 {
00124     rb_vm_t *vm = pvm;
00125     struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list, *prev_ume = 0, *curr_ume;
00126 
00127     while (ume) {
00128         if (ume->me->mark) {
00129             ume->me->mark = 0;
00130             prev_ume = ume;
00131             ume = ume->next;
00132         }
00133         else {
00134             rb_free_method_entry(ume->me);
00135 
00136             if (prev_ume == 0) {
00137                 vm->unlinked_method_entry_list = ume->next;
00138             }
00139             else {
00140                 prev_ume->next = ume->next;
00141             }
00142 
00143             curr_ume = ume;
00144             ume = ume->next;
00145             xfree(curr_ume);
00146         }
00147     }
00148 }
00149 
00150 static void
00151 release_method_definition(rb_method_definition_t *def)
00152 {
00153     if (def == 0)
00154         return;
00155     if (def->alias_count == 0) {
00156         if (def->type == VM_METHOD_TYPE_REFINED &&
00157             def->body.orig_me) {
00158             release_method_definition(def->body.orig_me->def);
00159             xfree(def->body.orig_me);
00160         }
00161         xfree(def);
00162     }
00163     else if (def->alias_count > 0) {
00164         def->alias_count--;
00165     }
00166 }
00167 
00168 void
00169 rb_free_method_entry(rb_method_entry_t *me)
00170 {
00171     release_method_definition(me->def);
00172     xfree(me);
00173 }
00174 
00175 static inline rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr);
00176 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
00177 
00178 static inline rb_method_entry_t *
00179 lookup_method_table(VALUE klass, ID id)
00180 {
00181     st_data_t body;
00182     st_table *m_tbl = RCLASS_M_TBL(klass);
00183     if (st_lookup(m_tbl, id, &body)) {
00184         return (rb_method_entry_t *) body;
00185     }
00186     else {
00187         return 0;
00188     }
00189 }
00190 
00191 static void
00192 make_method_entry_refined(rb_method_entry_t *me)
00193 {
00194     rb_method_definition_t *new_def;
00195 
00196     if (me->def && me->def->type == VM_METHOD_TYPE_REFINED)
00197         return;
00198 
00199     new_def = ALLOC(rb_method_definition_t);
00200     new_def->type = VM_METHOD_TYPE_REFINED;
00201     new_def->original_id = me->called_id;
00202     new_def->alias_count = 0;
00203     new_def->body.orig_me = ALLOC(rb_method_entry_t);
00204     *new_def->body.orig_me = *me;
00205     rb_vm_check_redefinition_opt_method(me, me->klass);
00206     if (me->def) me->def->alias_count++;
00207     me->flag = NOEX_WITH_SAFE(NOEX_PUBLIC);
00208     me->def = new_def;
00209 }
00210 
00211 void
00212 rb_add_refined_method_entry(VALUE refined_class, ID mid)
00213 {
00214     rb_method_entry_t *me = lookup_method_table(refined_class, mid);
00215 
00216     if (me) {
00217         make_method_entry_refined(me);
00218     }
00219     else {
00220         rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0,
00221                       NOEX_PUBLIC);
00222     }
00223 }
00224 
00225 static rb_method_entry_t *
00226 rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
00227                      rb_method_definition_t *def, rb_method_flag_t noex,
00228                      VALUE defined_class)
00229 {
00230     rb_method_entry_t *me;
00231 #if NOEX_NOREDEF
00232     VALUE rklass;
00233 #endif
00234     st_table *mtbl;
00235     st_data_t data;
00236     int make_refined = 0;
00237 
00238     if (NIL_P(klass)) {
00239         klass = rb_cObject;
00240     }
00241     if (rb_safe_level() >= 4 &&
00242         (klass == rb_cObject || !OBJ_UNTRUSTED(klass))) {
00243         rb_raise(rb_eSecurityError, "Insecure: can't define method");
00244     }
00245     if (!FL_TEST(klass, FL_SINGLETON) &&
00246         type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
00247         type != VM_METHOD_TYPE_ZSUPER &&
00248         (mid == idInitialize || mid == idInitialize_copy ||
00249          mid == idInitialize_clone || mid == idInitialize_dup ||
00250          mid == idRespond_to_missing)) {
00251         noex = NOEX_PRIVATE | noex;
00252     }
00253 
00254     rb_check_frozen(klass);
00255 #if NOEX_NOREDEF
00256     rklass = klass;
00257 #endif
00258     if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
00259         VALUE refined_class =
00260             rb_refinement_module_get_refined_class(klass);
00261 
00262         rb_add_refined_method_entry(refined_class, mid);
00263     }
00264     if (type == VM_METHOD_TYPE_REFINED) {
00265         rb_method_entry_t *old_me =
00266             lookup_method_table(RCLASS_ORIGIN(klass), mid);
00267         if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
00268     }
00269     else {
00270         klass = RCLASS_ORIGIN(klass);
00271     }
00272     mtbl = RCLASS_M_TBL(klass);
00273 
00274     /* check re-definition */
00275     if (st_lookup(mtbl, mid, &data)) {
00276         rb_method_entry_t *old_me = (rb_method_entry_t *)data;
00277         rb_method_definition_t *old_def = old_me->def;
00278 
00279         if (rb_method_definition_eq(old_def, def)) return old_me;
00280 #if NOEX_NOREDEF
00281         if (old_me->flag & NOEX_NOREDEF) {
00282             rb_raise(rb_eTypeError, "cannot redefine %"PRIsVALUE"#%"PRIsVALUE,
00283                      rb_class_name(rklass), rb_id2str(mid));
00284         }
00285 #endif
00286         rb_vm_check_redefinition_opt_method(old_me, klass);
00287         if (old_def->type == VM_METHOD_TYPE_REFINED)
00288             make_refined = 1;
00289 
00290         if (RTEST(ruby_verbose) &&
00291             type != VM_METHOD_TYPE_UNDEF &&
00292             old_def->alias_count == 0 &&
00293             old_def->type != VM_METHOD_TYPE_UNDEF &&
00294             old_def->type != VM_METHOD_TYPE_ZSUPER) {
00295             rb_iseq_t *iseq = 0;
00296 
00297             rb_warning("method redefined; discarding old %s", rb_id2name(mid));
00298             switch (old_def->type) {
00299               case VM_METHOD_TYPE_ISEQ:
00300                 iseq = old_def->body.iseq;
00301                 break;
00302               case VM_METHOD_TYPE_BMETHOD:
00303                 iseq = rb_proc_get_iseq(old_def->body.proc, 0);
00304                 break;
00305               default:
00306                 break;
00307             }
00308             if (iseq && !NIL_P(iseq->location.path)) {
00309                 int line = iseq->line_info_table ? rb_iseq_first_lineno(iseq) : 0;
00310                 rb_compile_warning(RSTRING_PTR(iseq->location.path), line,
00311                                    "previous definition of %s was here",
00312                                    rb_id2name(old_def->original_id));
00313             }
00314         }
00315 
00316         rb_unlink_method_entry(old_me);
00317     }
00318 
00319     me = ALLOC(rb_method_entry_t);
00320 
00321     rb_clear_cache_by_id(mid);
00322 
00323     me->flag = NOEX_WITH_SAFE(noex);
00324     me->mark = 0;
00325     me->called_id = mid;
00326     me->klass = defined_class;
00327     me->def = def;
00328     if (def) def->alias_count++;
00329 
00330     /* check mid */
00331     if (klass == rb_cObject && mid == idInitialize) {
00332         rb_warn("redefining Object#initialize may cause infinite loop");
00333     }
00334     /* check mid */
00335     if (mid == object_id || mid == id__send__) {
00336         if (type == VM_METHOD_TYPE_ISEQ && search_method(klass, mid, 0)) {
00337             rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid));
00338         }
00339     }
00340 
00341     if (make_refined) {
00342         make_method_entry_refined(me);
00343     }
00344 
00345     st_insert(mtbl, mid, (st_data_t) me);
00346 
00347     return me;
00348 }
00349 
00350 #define CALL_METHOD_HOOK(klass, hook, mid) do {         \
00351         const VALUE arg = ID2SYM(mid);                  \
00352         VALUE recv_class = (klass);                     \
00353         ID hook_id = (hook);                            \
00354         if (FL_TEST((klass), FL_SINGLETON)) {           \
00355             recv_class = rb_ivar_get((klass), attached);        \
00356             hook_id = singleton_##hook;                 \
00357         }                                               \
00358         rb_funcall2(recv_class, hook_id, 1, &arg);      \
00359     } while (0)
00360 
00361 static void
00362 method_added(VALUE klass, ID mid)
00363 {
00364     if (ruby_running) {
00365         CALL_METHOD_HOOK(klass, added, mid);
00366     }
00367 }
00368 
00369 static VALUE
00370 (*call_cfunc_invoker_func(int argc))(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *)
00371 {
00372     switch (argc) {
00373       case -2: return &call_cfunc_m2;
00374       case -1: return &call_cfunc_m1;
00375       case 0: return &call_cfunc_0;
00376       case 1: return &call_cfunc_1;
00377       case 2: return &call_cfunc_2;
00378       case 3: return &call_cfunc_3;
00379       case 4: return &call_cfunc_4;
00380       case 5: return &call_cfunc_5;
00381       case 6: return &call_cfunc_6;
00382       case 7: return &call_cfunc_7;
00383       case 8: return &call_cfunc_8;
00384       case 9: return &call_cfunc_9;
00385       case 10: return &call_cfunc_10;
00386       case 11: return &call_cfunc_11;
00387       case 12: return &call_cfunc_12;
00388       case 13: return &call_cfunc_13;
00389       case 14: return &call_cfunc_14;
00390       case 15: return &call_cfunc_15;
00391       default:
00392         rb_bug("call_cfunc_func: unsupported length: %d", argc);
00393     }
00394 }
00395 
00396 static void
00397 setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
00398 {
00399     cfunc->func = func;
00400     cfunc->argc = argc;
00401     cfunc->invoker = call_cfunc_invoker_func(argc);
00402 }
00403 
00404 rb_method_entry_t *
00405 rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
00406 {
00407     rb_thread_t *th;
00408     rb_control_frame_t *cfp;
00409     int line;
00410     rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex, klass);
00411     rb_method_definition_t *def = ALLOC(rb_method_definition_t);
00412     if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
00413         me->def->body.orig_me->def = def;
00414     }
00415     else {
00416         me->def = def;
00417     }
00418     def->type = type;
00419     def->original_id = mid;
00420     def->alias_count = 0;
00421     switch (type) {
00422       case VM_METHOD_TYPE_ISEQ:
00423         def->body.iseq = (rb_iseq_t *)opts;
00424         break;
00425       case VM_METHOD_TYPE_CFUNC:
00426         {
00427             rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts;
00428             setup_method_cfunc_struct(&def->body.cfunc, cfunc->func, cfunc->argc);
00429         }
00430         break;
00431       case VM_METHOD_TYPE_ATTRSET:
00432       case VM_METHOD_TYPE_IVAR:
00433         def->body.attr.id = (ID)opts;
00434         def->body.attr.location = Qfalse;
00435         th = GET_THREAD();
00436         cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00437         if (cfp && (line = rb_vm_get_sourceline(cfp))) {
00438             VALUE location = rb_ary_new3(2, cfp->iseq->location.path, INT2FIX(line));
00439             def->body.attr.location = rb_ary_freeze(location);
00440         }
00441         break;
00442       case VM_METHOD_TYPE_BMETHOD:
00443         def->body.proc = (VALUE)opts;
00444         break;
00445       case VM_METHOD_TYPE_NOTIMPLEMENTED:
00446         setup_method_cfunc_struct(&def->body.cfunc, rb_f_notimplement, -1);
00447         break;
00448       case VM_METHOD_TYPE_OPTIMIZED:
00449         def->body.optimize_type = (enum method_optimized_type)opts;
00450         break;
00451       case VM_METHOD_TYPE_ZSUPER:
00452       case VM_METHOD_TYPE_UNDEF:
00453         break;
00454       case VM_METHOD_TYPE_REFINED:
00455         def->body.orig_me = (rb_method_entry_t *) opts;
00456         break;
00457       default:
00458         rb_bug("rb_add_method: unsupported method type (%d)\n", type);
00459     }
00460     if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
00461         method_added(klass, mid);
00462     }
00463     return me;
00464 }
00465 
00466 static rb_method_entry_t *
00467 method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me,
00468                  rb_method_flag_t noex, VALUE defined_class)
00469 {
00470     rb_method_type_t type = me->def ? me->def->type : VM_METHOD_TYPE_UNDEF;
00471     rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex,
00472                                                     defined_class);
00473     method_added(klass, mid);
00474     return newme;
00475 }
00476 
00477 rb_method_entry_t *
00478 rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_flag_t noex)
00479 {
00480     return method_entry_set(klass, mid, me, noex, klass);
00481 }
00482 
00483 #define UNDEF_ALLOC_FUNC ((rb_alloc_func_t)-1)
00484 
00485 void
00486 rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
00487 {
00488     Check_Type(klass, T_CLASS);
00489     RCLASS_EXT(klass)->allocator = func;
00490 }
00491 
00492 void
00493 rb_undef_alloc_func(VALUE klass)
00494 {
00495     rb_define_alloc_func(klass, UNDEF_ALLOC_FUNC);
00496 }
00497 
00498 rb_alloc_func_t
00499 rb_get_alloc_func(VALUE klass)
00500 {
00501     Check_Type(klass, T_CLASS);
00502 
00503     for (; klass; klass = RCLASS_SUPER(klass)) {
00504         rb_alloc_func_t allocator = RCLASS_EXT(klass)->allocator;
00505         if (allocator == UNDEF_ALLOC_FUNC) break;
00506         if (allocator) return allocator;
00507     }
00508     return 0;
00509 }
00510 
00511 static inline rb_method_entry_t*
00512 search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
00513 {
00514     rb_method_entry_t *me;
00515 
00516     for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
00517         if ((me = lookup_method_table(klass, id)) != 0) break;
00518     }
00519 
00520     if (defined_class_ptr)
00521         *defined_class_ptr = klass;
00522     return me;
00523 }
00524 
00525 /*
00526  * search method entry without the method cache.
00527  *
00528  * if you need method entry with method cache (normal case), use
00529  * rb_method_entry() simply.
00530  */
00531 rb_method_entry_t *
00532 rb_method_entry_get_without_cache(VALUE klass, ID id,
00533                                   VALUE *defined_class_ptr)
00534 {
00535     VALUE defined_class;
00536     rb_method_entry_t *me = search_method(klass, id, &defined_class);
00537 
00538     if (me && me->klass) {
00539         switch (BUILTIN_TYPE(me->klass)) {
00540           case T_CLASS:
00541             if (RBASIC(klass)->flags & FL_SINGLETON) break;
00542             /* fall through */
00543           case T_ICLASS:
00544             defined_class = me->klass;
00545         }
00546     }
00547 
00548     if (ruby_running) {
00549         struct cache_entry *ent;
00550         ent = cache + EXPR1(klass, id);
00551         ent->filled_version = GET_VM_STATE_VERSION();
00552         ent->klass = klass;
00553         ent->defined_class = defined_class;
00554 
00555         if (UNDEFINED_METHOD_ENTRY_P(me)) {
00556             ent->mid = id;
00557             ent->me = 0;
00558             me = 0;
00559         }
00560         else {
00561             ent->mid = id;
00562             ent->me = me;
00563         }
00564     }
00565 
00566     if (defined_class_ptr)
00567         *defined_class_ptr = defined_class;
00568     return me;
00569 }
00570 
00571 rb_method_entry_t *
00572 rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
00573 {
00574 #if OPT_GLOBAL_METHOD_CACHE
00575     struct cache_entry *ent;
00576 
00577     ent = cache + EXPR1(klass, id);
00578     if (ent->filled_version == GET_VM_STATE_VERSION() &&
00579         ent->mid == id && ent->klass == klass) {
00580         if (defined_class_ptr)
00581             *defined_class_ptr = ent->defined_class;
00582         return ent->me;
00583     }
00584 #endif
00585 
00586     return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
00587 }
00588 
00589 static rb_method_entry_t *
00590 get_original_method_entry(VALUE refinements,
00591                           const rb_method_entry_t *me,
00592                           VALUE *defined_class_ptr)
00593 {
00594     if (me->def->body.orig_me) {
00595         return me->def->body.orig_me;
00596     }
00597     else {
00598         rb_method_entry_t *tmp_me;
00599         tmp_me = rb_method_entry(RCLASS_SUPER(me->klass), me->called_id,
00600                                  defined_class_ptr);
00601         return rb_resolve_refined_method(refinements, tmp_me,
00602                                          defined_class_ptr);
00603     }
00604 }
00605 
00606 rb_method_entry_t *
00607 rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me,
00608                           VALUE *defined_class_ptr)
00609 {
00610     if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
00611         VALUE refinement;
00612         rb_method_entry_t *tmp_me;
00613 
00614         refinement = find_refinement(refinements, me->klass);
00615         if (NIL_P(refinement)) {
00616             return get_original_method_entry(refinements, me,
00617                                              defined_class_ptr);
00618         }
00619         tmp_me = rb_method_entry(refinement, me->called_id,
00620                                  defined_class_ptr);
00621         if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
00622             return tmp_me;
00623         }
00624         else {
00625             return get_original_method_entry(refinements, me,
00626                                              defined_class_ptr);
00627         }
00628     }
00629     else {
00630         return (rb_method_entry_t *)me;
00631     }
00632 }
00633 
00634 rb_method_entry_t *
00635 rb_method_entry_with_refinements(VALUE klass, ID id,
00636                                  VALUE *defined_class_ptr)
00637 {
00638     VALUE defined_class;
00639     rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
00640 
00641     if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
00642         NODE *cref = rb_vm_cref();
00643         VALUE refinements = cref ? cref->nd_refinements : Qnil;
00644 
00645         me = rb_resolve_refined_method(refinements, me, &defined_class);
00646     }
00647     if (defined_class_ptr)
00648         *defined_class_ptr = defined_class;
00649     return me;
00650 }
00651 
00652 rb_method_entry_t *
00653 rb_method_entry_without_refinements(VALUE klass, ID id,
00654                                     VALUE *defined_class_ptr)
00655 {
00656     VALUE defined_class;
00657     rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
00658 
00659     if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
00660         me = rb_resolve_refined_method(Qnil, me, &defined_class);
00661     }
00662     if (defined_class_ptr)
00663         *defined_class_ptr = defined_class;
00664     if (UNDEFINED_METHOD_ENTRY_P(me)) {
00665         return 0;
00666     }
00667     else {
00668         return me;
00669     }
00670 }
00671 
00672 static void
00673 remove_method(VALUE klass, ID mid)
00674 {
00675     st_data_t key, data;
00676     rb_method_entry_t *me = 0;
00677     VALUE self = klass;
00678 
00679     klass = RCLASS_ORIGIN(klass);
00680     if (klass == rb_cObject) {
00681         rb_secure(4);
00682     }
00683     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
00684         rb_raise(rb_eSecurityError, "Insecure: can't remove method");
00685     }
00686     rb_check_frozen(klass);
00687     if (mid == object_id || mid == id__send__ || mid == idInitialize) {
00688         rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
00689     }
00690 
00691     if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
00692         !(me = (rb_method_entry_t *)data) ||
00693         (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
00694         rb_name_error(mid, "method `%s' not defined in %s",
00695                       rb_id2name(mid), rb_class2name(klass));
00696     }
00697     key = (st_data_t)mid;
00698     st_delete(RCLASS_M_TBL(klass), &key, &data);
00699 
00700     rb_vm_check_redefinition_opt_method(me, klass);
00701     rb_clear_cache_for_undef(klass, mid);
00702     rb_unlink_method_entry(me);
00703 
00704     CALL_METHOD_HOOK(self, removed, mid);
00705 }
00706 
00707 void
00708 rb_remove_method_id(VALUE klass, ID mid)
00709 {
00710     remove_method(klass, mid);
00711 }
00712 
00713 void
00714 rb_remove_method(VALUE klass, const char *name)
00715 {
00716     remove_method(klass, rb_intern(name));
00717 }
00718 
00719 /*
00720  *  call-seq:
00721  *     remove_method(symbol)   -> self
00722  *
00723  *  Removes the method identified by _symbol_ from the current
00724  *  class. For an example, see <code>Module.undef_method</code>.
00725  */
00726 
00727 static VALUE
00728 rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
00729 {
00730     int i;
00731 
00732     for (i = 0; i < argc; i++) {
00733         VALUE v = argv[i];
00734         ID id = rb_check_id(&v);
00735         if (!id) {
00736             rb_name_error_str(v, "method `%s' not defined in %s",
00737                               RSTRING_PTR(v), rb_class2name(mod));
00738         }
00739         remove_method(mod, id);
00740     }
00741     return mod;
00742 }
00743 
00744 #undef rb_disable_super
00745 #undef rb_enable_super
00746 
00747 void
00748 rb_disable_super(VALUE klass, const char *name)
00749 {
00750     /* obsolete - no use */
00751 }
00752 
00753 void
00754 rb_enable_super(VALUE klass, const char *name)
00755 {
00756     rb_warning("rb_enable_super() is obsolete");
00757 }
00758 
00759 static void
00760 rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
00761 {
00762     rb_method_entry_t *me;
00763     VALUE defined_class;
00764 
00765     if (klass == rb_cObject) {
00766         rb_secure(4);
00767     }
00768 
00769     me = search_method(klass, name, &defined_class);
00770     if (!me && RB_TYPE_P(klass, T_MODULE)) {
00771         me = search_method(rb_cObject, name, &defined_class);
00772     }
00773 
00774     if (UNDEFINED_METHOD_ENTRY_P(me)) {
00775         rb_print_undef(klass, name, 0);
00776     }
00777 
00778     if (me->flag != noex) {
00779         rb_vm_check_redefinition_opt_method(me, klass);
00780 
00781         if (klass == defined_class ||
00782             RCLASS_ORIGIN(klass) == defined_class) {
00783             me->flag = noex;
00784             if (me->def->type == VM_METHOD_TYPE_REFINED) {
00785                 me->def->body.orig_me->flag = noex;
00786             }
00787         }
00788         else {
00789             rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
00790         }
00791     }
00792 }
00793 
00794 int
00795 rb_method_boundp(VALUE klass, ID id, int ex)
00796 {
00797     rb_method_entry_t *me =
00798         rb_method_entry_without_refinements(klass, id, 0);
00799 
00800     if (me != 0) {
00801         if ((ex & ~NOEX_RESPONDS) &&
00802             ((me->flag & NOEX_PRIVATE) ||
00803              ((ex & NOEX_RESPONDS) && (me->flag & NOEX_PROTECTED)))) {
00804             return 0;
00805         }
00806         if (!me->def) return 0;
00807         if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
00808             if (ex & NOEX_RESPONDS) return 2;
00809             return 0;
00810         }
00811         return 1;
00812     }
00813     return 0;
00814 }
00815 
00816 void
00817 rb_attr(VALUE klass, ID id, int read, int write, int ex)
00818 {
00819     const char *name;
00820     ID attriv;
00821     VALUE aname;
00822     rb_method_flag_t noex;
00823 
00824     if (!ex) {
00825         noex = NOEX_PUBLIC;
00826     }
00827     else {
00828         if (SCOPE_TEST(NOEX_PRIVATE)) {
00829             noex = NOEX_PRIVATE;
00830             rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
00831                        "attribute accessor as module_function" :
00832                        "private attribute?");
00833         }
00834         else if (SCOPE_TEST(NOEX_PROTECTED)) {
00835             noex = NOEX_PROTECTED;
00836         }
00837         else {
00838             noex = NOEX_PUBLIC;
00839         }
00840     }
00841 
00842     if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
00843         rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
00844     }
00845     name = rb_id2name(id);
00846     if (!name) {
00847         rb_raise(rb_eArgError, "argument needs to be symbol or string");
00848     }
00849     aname = rb_sprintf("@%s", name);
00850     rb_enc_copy(aname, rb_id2str(id));
00851     attriv = rb_intern_str(aname);
00852     if (read) {
00853         rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, noex);
00854     }
00855     if (write) {
00856         rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, noex);
00857     }
00858 }
00859 
00860 void
00861 rb_undef(VALUE klass, ID id)
00862 {
00863     rb_method_entry_t *me;
00864 
00865     if (NIL_P(klass)) {
00866         rb_raise(rb_eTypeError, "no class to undef method");
00867     }
00868     if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
00869         rb_secure(4);
00870     }
00871     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
00872         rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
00873     }
00874     rb_frozen_class_p(klass);
00875     if (id == object_id || id == id__send__ || id == idInitialize) {
00876         rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
00877     }
00878 
00879     me = search_method(klass, id, 0);
00880 
00881     if (UNDEFINED_METHOD_ENTRY_P(me) ||
00882         (me->def->type == VM_METHOD_TYPE_REFINED &&
00883          UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) {
00884         const char *s0 = " class";
00885         VALUE c = klass;
00886 
00887         if (FL_TEST(c, FL_SINGLETON)) {
00888             VALUE obj = rb_ivar_get(klass, attached);
00889 
00890             if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) {
00891                 c = obj;
00892                 s0 = "";
00893             }
00894         }
00895         else if (RB_TYPE_P(c, T_MODULE)) {
00896             s0 = " module";
00897         }
00898         rb_name_error(id, "undefined method `%"PRIsVALUE"' for%s `%"PRIsVALUE"'",
00899                       QUOTE_ID(id), s0, rb_class_name(c));
00900     }
00901 
00902     rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
00903 
00904     CALL_METHOD_HOOK(klass, undefined, id);
00905 }
00906 
00907 /*
00908  *  call-seq:
00909  *     undef_method(symbol)    -> self
00910  *
00911  *  Prevents the current class from responding to calls to the named
00912  *  method. Contrast this with <code>remove_method</code>, which deletes
00913  *  the method from the particular class; Ruby will still search
00914  *  superclasses and mixed-in modules for a possible receiver.
00915  *
00916  *     class Parent
00917  *       def hello
00918  *         puts "In parent"
00919  *       end
00920  *     end
00921  *     class Child < Parent
00922  *       def hello
00923  *         puts "In child"
00924  *       end
00925  *     end
00926  *
00927  *
00928  *     c = Child.new
00929  *     c.hello
00930  *
00931  *
00932  *     class Child
00933  *       remove_method :hello  # remove from child, still in parent
00934  *     end
00935  *     c.hello
00936  *
00937  *
00938  *     class Child
00939  *       undef_method :hello   # prevent any calls to 'hello'
00940  *     end
00941  *     c.hello
00942  *
00943  *  <em>produces:</em>
00944  *
00945  *     In child
00946  *     In parent
00947  *     prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError)
00948  */
00949 
00950 static VALUE
00951 rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
00952 {
00953     int i;
00954     for (i = 0; i < argc; i++) {
00955         VALUE v = argv[i];
00956         ID id = rb_check_id(&v);
00957         if (!id) {
00958             rb_method_name_error(mod, v);
00959         }
00960         rb_undef(mod, id);
00961     }
00962     return mod;
00963 }
00964 
00965 /*
00966  *  call-seq:
00967  *     mod.method_defined?(symbol)    -> true or false
00968  *
00969  *  Returns +true+ if the named method is defined by
00970  *  _mod_ (or its included modules and, if _mod_ is a class,
00971  *  its ancestors). Public and protected methods are matched.
00972  *
00973  *     module A
00974  *       def method1()  end
00975  *     end
00976  *     class B
00977  *       def method2()  end
00978  *     end
00979  *     class C < B
00980  *       include A
00981  *       def method3()  end
00982  *     end
00983  *
00984  *     A.method_defined? :method1    #=> true
00985  *     C.method_defined? "method1"   #=> true
00986  *     C.method_defined? "method2"   #=> true
00987  *     C.method_defined? "method3"   #=> true
00988  *     C.method_defined? "method4"   #=> false
00989  */
00990 
00991 static VALUE
00992 rb_mod_method_defined(VALUE mod, VALUE mid)
00993 {
00994     ID id = rb_check_id(&mid);
00995     if (!id || !rb_method_boundp(mod, id, 1)) {
00996         return Qfalse;
00997     }
00998     return Qtrue;
00999 
01000 }
01001 
01002 #define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
01003 
01004 static VALUE
01005 check_definition(VALUE mod, VALUE mid, rb_method_flag_t noex)
01006 {
01007     const rb_method_entry_t *me;
01008     ID id = rb_check_id(&mid);
01009     if (!id) return Qfalse;
01010     me = rb_method_entry(mod, id, 0);
01011     if (me) {
01012         if (VISI_CHECK(me->flag, noex))
01013             return Qtrue;
01014     }
01015     return Qfalse;
01016 }
01017 
01018 /*
01019  *  call-seq:
01020  *     mod.public_method_defined?(symbol)   -> true or false
01021  *
01022  *  Returns +true+ if the named public method is defined by
01023  *  _mod_ (or its included modules and, if _mod_ is a class,
01024  *  its ancestors).
01025  *
01026  *     module A
01027  *       def method1()  end
01028  *     end
01029  *     class B
01030  *       protected
01031  *       def method2()  end
01032  *     end
01033  *     class C < B
01034  *       include A
01035  *       def method3()  end
01036  *     end
01037  *
01038  *     A.method_defined? :method1           #=> true
01039  *     C.public_method_defined? "method1"   #=> true
01040  *     C.public_method_defined? "method2"   #=> false
01041  *     C.method_defined? "method2"          #=> true
01042  */
01043 
01044 static VALUE
01045 rb_mod_public_method_defined(VALUE mod, VALUE mid)
01046 {
01047     return check_definition(mod, mid, NOEX_PUBLIC);
01048 }
01049 
01050 /*
01051  *  call-seq:
01052  *     mod.private_method_defined?(symbol)    -> true or false
01053  *
01054  *  Returns +true+ if the named private method is defined by
01055  *  _ mod_ (or its included modules and, if _mod_ is a class,
01056  *  its ancestors).
01057  *
01058  *     module A
01059  *       def method1()  end
01060  *     end
01061  *     class B
01062  *       private
01063  *       def method2()  end
01064  *     end
01065  *     class C < B
01066  *       include A
01067  *       def method3()  end
01068  *     end
01069  *
01070  *     A.method_defined? :method1            #=> true
01071  *     C.private_method_defined? "method1"   #=> false
01072  *     C.private_method_defined? "method2"   #=> true
01073  *     C.method_defined? "method2"           #=> false
01074  */
01075 
01076 static VALUE
01077 rb_mod_private_method_defined(VALUE mod, VALUE mid)
01078 {
01079     return check_definition(mod, mid, NOEX_PRIVATE);
01080 }
01081 
01082 /*
01083  *  call-seq:
01084  *     mod.protected_method_defined?(symbol)   -> true or false
01085  *
01086  *  Returns +true+ if the named protected method is defined
01087  *  by _mod_ (or its included modules and, if _mod_ is a
01088  *  class, its ancestors).
01089  *
01090  *     module A
01091  *       def method1()  end
01092  *     end
01093  *     class B
01094  *       protected
01095  *       def method2()  end
01096  *     end
01097  *     class C < B
01098  *       include A
01099  *       def method3()  end
01100  *     end
01101  *
01102  *     A.method_defined? :method1              #=> true
01103  *     C.protected_method_defined? "method1"   #=> false
01104  *     C.protected_method_defined? "method2"   #=> true
01105  *     C.method_defined? "method2"             #=> true
01106  */
01107 
01108 static VALUE
01109 rb_mod_protected_method_defined(VALUE mod, VALUE mid)
01110 {
01111     return check_definition(mod, mid, NOEX_PROTECTED);
01112 }
01113 
01114 int
01115 rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
01116 {
01117     return rb_method_definition_eq(m1->def, m2->def);
01118 }
01119 
01120 static int
01121 rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
01122 {
01123     if (d1 && d1->type == VM_METHOD_TYPE_REFINED && d1->body.orig_me)
01124         d1 = d1->body.orig_me->def;
01125     if (d2 && d2->type == VM_METHOD_TYPE_REFINED && d2->body.orig_me)
01126         d2 = d2->body.orig_me->def;
01127     if (d1 == d2) return 1;
01128     if (!d1 || !d2) return 0;
01129     if (d1->type != d2->type) {
01130         return 0;
01131     }
01132     switch (d1->type) {
01133       case VM_METHOD_TYPE_ISEQ:
01134         return d1->body.iseq == d2->body.iseq;
01135       case VM_METHOD_TYPE_CFUNC:
01136         return
01137           d1->body.cfunc.func == d2->body.cfunc.func &&
01138           d1->body.cfunc.argc == d2->body.cfunc.argc;
01139       case VM_METHOD_TYPE_ATTRSET:
01140       case VM_METHOD_TYPE_IVAR:
01141         return d1->body.attr.id == d2->body.attr.id;
01142       case VM_METHOD_TYPE_BMETHOD:
01143         return RTEST(rb_equal(d1->body.proc, d2->body.proc));
01144       case VM_METHOD_TYPE_MISSING:
01145         return d1->original_id == d2->original_id;
01146       case VM_METHOD_TYPE_ZSUPER:
01147       case VM_METHOD_TYPE_NOTIMPLEMENTED:
01148       case VM_METHOD_TYPE_UNDEF:
01149         return 1;
01150       case VM_METHOD_TYPE_OPTIMIZED:
01151         return d1->body.optimize_type == d2->body.optimize_type;
01152       default:
01153         rb_bug("rb_method_entry_eq: unsupported method type (%d)\n", d1->type);
01154         return 0;
01155     }
01156 }
01157 
01158 static st_index_t
01159 rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
01160 {
01161   again:
01162     hash = rb_hash_uint(hash, def->type);
01163     switch (def->type) {
01164       case VM_METHOD_TYPE_ISEQ:
01165         return rb_hash_uint(hash, (st_index_t)def->body.iseq);
01166       case VM_METHOD_TYPE_CFUNC:
01167         hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
01168         return rb_hash_uint(hash, def->body.cfunc.argc);
01169       case VM_METHOD_TYPE_ATTRSET:
01170       case VM_METHOD_TYPE_IVAR:
01171         return rb_hash_uint(hash, def->body.attr.id);
01172       case VM_METHOD_TYPE_BMETHOD:
01173         return rb_hash_proc(hash, def->body.proc);
01174       case VM_METHOD_TYPE_MISSING:
01175         return rb_hash_uint(hash, def->original_id);
01176       case VM_METHOD_TYPE_ZSUPER:
01177       case VM_METHOD_TYPE_NOTIMPLEMENTED:
01178       case VM_METHOD_TYPE_UNDEF:
01179         return hash;
01180       case VM_METHOD_TYPE_OPTIMIZED:
01181         return rb_hash_uint(hash, def->body.optimize_type);
01182       case VM_METHOD_TYPE_REFINED:
01183         if (def->body.orig_me) {
01184             def = def->body.orig_me->def;
01185             goto again;
01186         }
01187         else {
01188             return hash;
01189         }
01190       default:
01191         rb_bug("rb_hash_method_definition: unsupported method type (%d)\n", def->type);
01192     }
01193     return hash;
01194 }
01195 
01196 st_index_t
01197 rb_hash_method_entry(st_index_t hash, const rb_method_entry_t *me)
01198 {
01199     return rb_hash_method_definition(hash, me->def);
01200 }
01201 
01202 void
01203 rb_alias(VALUE klass, ID name, ID def)
01204 {
01205     VALUE target_klass = klass;
01206     VALUE defined_class;
01207     rb_method_entry_t *orig_me;
01208     rb_method_flag_t flag = NOEX_UNDEF;
01209 
01210     if (NIL_P(klass)) {
01211         rb_raise(rb_eTypeError, "no class to make alias");
01212     }
01213 
01214     rb_frozen_class_p(klass);
01215     if (klass == rb_cObject) {
01216         rb_secure(4);
01217     }
01218 
01219   again:
01220     orig_me = search_method(klass, def, &defined_class);
01221 
01222     if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
01223         if ((!RB_TYPE_P(klass, T_MODULE)) ||
01224             (orig_me = search_method(rb_cObject, def, 0),
01225              UNDEFINED_METHOD_ENTRY_P(orig_me))) {
01226             rb_print_undef(klass, def, 0);
01227         }
01228     }
01229     if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
01230         klass = RCLASS_SUPER(klass);
01231         def = orig_me->def->original_id;
01232         flag = orig_me->flag;
01233         goto again;
01234     }
01235     if (RB_TYPE_P(defined_class, T_ICLASS)) {
01236         VALUE real_class = RBASIC(defined_class)->klass;
01237         if (real_class && RCLASS_ORIGIN(real_class) == defined_class)
01238             defined_class = real_class;
01239     }
01240 
01241     if (flag == NOEX_UNDEF) flag = orig_me->flag;
01242     method_entry_set(target_klass, name, orig_me, flag, defined_class);
01243 }
01244 
01245 /*
01246  *  call-seq:
01247  *     alias_method(new_name, old_name)   -> self
01248  *
01249  *  Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can
01250  *  be used to retain access to methods that are overridden.
01251  *
01252  *     module Mod
01253  *       alias_method :orig_exit, :exit
01254  *       def exit(code=0)
01255  *         puts "Exiting with code #{code}"
01256  *         orig_exit(code)
01257  *       end
01258  *     end
01259  *     include Mod
01260  *     exit(99)
01261  *
01262  *  <em>produces:</em>
01263  *
01264  *     Exiting with code 99
01265  */
01266 
01267 static VALUE
01268 rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
01269 {
01270     ID oldid = rb_check_id(&oldname);
01271     if (!oldid) {
01272         rb_print_undef_str(mod, oldname);
01273     }
01274     rb_alias(mod, rb_to_id(newname), oldid);
01275     return mod;
01276 }
01277 
01278 static void
01279 secure_visibility(VALUE self)
01280 {
01281     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(self)) {
01282         rb_raise(rb_eSecurityError,
01283                  "Insecure: can't change method visibility");
01284     }
01285 }
01286 
01287 static void
01288 set_method_visibility(VALUE self, int argc, VALUE *argv, rb_method_flag_t ex)
01289 {
01290     int i;
01291     secure_visibility(self);
01292 
01293     if (argc == 0) {
01294         rb_warning("%s with no argument is just ignored", rb_id2name(rb_frame_callee()));
01295     }
01296 
01297     for (i = 0; i < argc; i++) {
01298         VALUE v = argv[i];
01299         ID id = rb_check_id(&v);
01300         if (!id) {
01301             rb_print_undef_str(self, v);
01302         }
01303         rb_export_method(self, id, ex);
01304     }
01305     rb_clear_cache_by_class(self);
01306 }
01307 
01308 /*
01309  *  call-seq:
01310  *     public                 -> self
01311  *     public(symbol, ...)    -> self
01312  *
01313  *  With no arguments, sets the default visibility for subsequently
01314  *  defined methods to public. With arguments, sets the named methods to
01315  *  have public visibility.
01316  */
01317 
01318 static VALUE
01319 rb_mod_public(int argc, VALUE *argv, VALUE module)
01320 {
01321     secure_visibility(module);
01322     if (argc == 0) {
01323         SCOPE_SET(NOEX_PUBLIC);
01324     }
01325     else {
01326         set_method_visibility(module, argc, argv, NOEX_PUBLIC);
01327     }
01328     return module;
01329 }
01330 
01331 /*
01332  *  call-seq:
01333  *     protected                -> self
01334  *     protected(symbol, ...)   -> self
01335  *
01336  *  With no arguments, sets the default visibility for subsequently
01337  *  defined methods to protected. With arguments, sets the named methods
01338  *  to have protected visibility.
01339  */
01340 
01341 static VALUE
01342 rb_mod_protected(int argc, VALUE *argv, VALUE module)
01343 {
01344     secure_visibility(module);
01345     if (argc == 0) {
01346         SCOPE_SET(NOEX_PROTECTED);
01347     }
01348     else {
01349         set_method_visibility(module, argc, argv, NOEX_PROTECTED);
01350     }
01351     return module;
01352 }
01353 
01354 /*
01355  *  call-seq:
01356  *     private                 -> self
01357  *     private(symbol, ...)    -> self
01358  *
01359  *  With no arguments, sets the default visibility for subsequently
01360  *  defined methods to private. With arguments, sets the named methods
01361  *  to have private visibility.
01362  *
01363  *     module Mod
01364  *       def a()  end
01365  *       def b()  end
01366  *       private
01367  *       def c()  end
01368  *       private :a
01369  *     end
01370  *     Mod.private_instance_methods   #=> [:a, :c]
01371  */
01372 
01373 static VALUE
01374 rb_mod_private(int argc, VALUE *argv, VALUE module)
01375 {
01376     secure_visibility(module);
01377     if (argc == 0) {
01378         SCOPE_SET(NOEX_PRIVATE);
01379     }
01380     else {
01381         set_method_visibility(module, argc, argv, NOEX_PRIVATE);
01382     }
01383     return module;
01384 }
01385 
01386 /*
01387  *  call-seq:
01388  *     mod.public_class_method(symbol, ...)    -> mod
01389  *
01390  *  Makes a list of existing class methods public.
01391  */
01392 
01393 static VALUE
01394 rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
01395 {
01396     set_method_visibility(rb_singleton_class(obj), argc, argv, NOEX_PUBLIC);
01397     return obj;
01398 }
01399 
01400 /*
01401  *  call-seq:
01402  *     mod.private_class_method(symbol, ...)   -> mod
01403  *
01404  *  Makes existing class methods private. Often used to hide the default
01405  *  constructor <code>new</code>.
01406  *
01407  *     class SimpleSingleton  # Not thread safe
01408  *       private_class_method :new
01409  *       def SimpleSingleton.create(*args, &block)
01410  *         @me = new(*args, &block) if ! @me
01411  *         @me
01412  *       end
01413  *     end
01414  */
01415 
01416 static VALUE
01417 rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
01418 {
01419     set_method_visibility(rb_singleton_class(obj), argc, argv, NOEX_PRIVATE);
01420     return obj;
01421 }
01422 
01423 /*
01424  *  call-seq:
01425  *     public
01426  *     public(symbol, ...)
01427  *
01428  *  With no arguments, sets the default visibility for subsequently
01429  *  defined methods to public. With arguments, sets the named methods to
01430  *  have public visibility.
01431  */
01432 
01433 static VALUE
01434 top_public(int argc, VALUE *argv)
01435 {
01436     return rb_mod_public(argc, argv, rb_cObject);
01437 }
01438 
01439 static VALUE
01440 top_private(int argc, VALUE *argv)
01441 {
01442     return rb_mod_private(argc, argv, rb_cObject);
01443 }
01444 
01445 /*
01446  *  call-seq:
01447  *     module_function(symbol, ...)    -> self
01448  *
01449  *  Creates module functions for the named methods. These functions may
01450  *  be called with the module as a receiver, and also become available
01451  *  as instance methods to classes that mix in the module. Module
01452  *  functions are copies of the original, and so may be changed
01453  *  independently. The instance-method versions are made private. If
01454  *  used with no arguments, subsequently defined methods become module
01455  *  functions.
01456  *
01457  *     module Mod
01458  *       def one
01459  *         "This is one"
01460  *       end
01461  *       module_function :one
01462  *     end
01463  *     class Cls
01464  *       include Mod
01465  *       def call_one
01466  *         one
01467  *       end
01468  *     end
01469  *     Mod.one     #=> "This is one"
01470  *     c = Cls.new
01471  *     c.call_one  #=> "This is one"
01472  *     module Mod
01473  *       def one
01474  *         "This is the new one"
01475  *       end
01476  *     end
01477  *     Mod.one     #=> "This is one"
01478  *     c.call_one  #=> "This is the new one"
01479  */
01480 
01481 static VALUE
01482 rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
01483 {
01484     int i;
01485     ID id;
01486     const rb_method_entry_t *me;
01487 
01488     if (!RB_TYPE_P(module, T_MODULE)) {
01489         rb_raise(rb_eTypeError, "module_function must be called for modules");
01490     }
01491 
01492     secure_visibility(module);
01493     if (argc == 0) {
01494         SCOPE_SET(NOEX_MODFUNC);
01495         return module;
01496     }
01497 
01498     set_method_visibility(module, argc, argv, NOEX_PRIVATE);
01499 
01500     for (i = 0; i < argc; i++) {
01501         VALUE m = module;
01502 
01503         id = rb_to_id(argv[i]);
01504         for (;;) {
01505             me = search_method(m, id, 0);
01506             if (me == 0) {
01507                 me = search_method(rb_cObject, id, 0);
01508             }
01509             if (UNDEFINED_METHOD_ENTRY_P(me)) {
01510                 rb_print_undef(module, id, 0);
01511             }
01512             if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
01513                 break; /* normal case: need not to follow 'super' link */
01514             }
01515             m = RCLASS_SUPER(m);
01516             if (!m)
01517                 break;
01518         }
01519         rb_method_entry_set(rb_singleton_class(module), id, me, NOEX_PUBLIC);
01520     }
01521     return module;
01522 }
01523 
01524 int
01525 rb_method_basic_definition_p(VALUE klass, ID id)
01526 {
01527     const rb_method_entry_t *me = rb_method_entry(klass, id, 0);
01528     if (me && (me->flag & NOEX_BASIC))
01529         return 1;
01530     return 0;
01531 }
01532 
01533 static inline int
01534 basic_obj_respond_to(VALUE obj, ID id, int pub)
01535 {
01536     VALUE klass = CLASS_OF(obj);
01537     VALUE args[2];
01538 
01539     switch (rb_method_boundp(klass, id, pub|NOEX_RESPONDS)) {
01540       case 2:
01541         return FALSE;
01542       case 0:
01543         args[0] = ID2SYM(id);
01544         args[1] = pub ? Qfalse : Qtrue;
01545         return RTEST(rb_funcall2(obj, idRespond_to_missing, 2, args));
01546       default:
01547         return TRUE;
01548     }
01549 }
01550 
01551 int
01552 rb_obj_respond_to(VALUE obj, ID id, int priv)
01553 {
01554     VALUE klass = CLASS_OF(obj);
01555 
01556     if (rb_method_basic_definition_p(klass, idRespond_to)) {
01557         return basic_obj_respond_to(obj, id, !RTEST(priv));
01558     }
01559     else {
01560         int argc = 1;
01561         VALUE args[2];
01562         args[0] = ID2SYM(id);
01563         args[1] = Qtrue;
01564         if (priv) {
01565             if (rb_obj_method_arity(obj, idRespond_to) != 1) {
01566                 argc = 2;
01567             }
01568             else if (!NIL_P(ruby_verbose)) {
01569                 VALUE klass = CLASS_OF(obj);
01570                 VALUE location = rb_mod_method_location(klass, idRespond_to);
01571                 rb_warn("%"PRIsVALUE"%c""respond_to?(:%"PRIsVALUE") is"
01572                         " old fashion which takes only one parameter",
01573                         (FL_TEST(klass, FL_SINGLETON) ? obj : klass),
01574                         (FL_TEST(klass, FL_SINGLETON) ? '.' : '#'),
01575                         QUOTE_ID(id));
01576                 if (!NIL_P(location)) {
01577                     VALUE path = RARRAY_PTR(location)[0];
01578                     VALUE line = RARRAY_PTR(location)[1];
01579                     if (!NIL_P(path)) {
01580                         rb_compile_warn(RSTRING_PTR(path), NUM2INT(line),
01581                                         "respond_to? is defined here");
01582                     }
01583                 }
01584             }
01585         }
01586         return RTEST(rb_funcall2(obj, idRespond_to, argc,  args));
01587     }
01588 }
01589 
01590 int
01591 rb_respond_to(VALUE obj, ID id)
01592 {
01593     return rb_obj_respond_to(obj, id, FALSE);
01594 }
01595 
01596 
01597 /*
01598  *  call-seq:
01599  *     obj.respond_to?(symbol, include_all=false) -> true or false
01600  *
01601  *  Returns +true+ if _obj_ responds to the given method.  Private and
01602  *  protected methods are included in the search only if the optional
01603  *  second parameter evaluates to +true+.
01604  *
01605  *  If the method is not implemented,
01606  *  as Process.fork on Windows, File.lchmod on GNU/Linux, etc.,
01607  *  false is returned.
01608  *
01609  *  If the method is not defined, <code>respond_to_missing?</code>
01610  *  method is called and the result is returned.
01611  */
01612 
01613 static VALUE
01614 obj_respond_to(int argc, VALUE *argv, VALUE obj)
01615 {
01616     VALUE mid, priv;
01617     ID id;
01618 
01619     rb_scan_args(argc, argv, "11", &mid, &priv);
01620     if (!(id = rb_check_id(&mid))) {
01621         if (!rb_method_basic_definition_p(CLASS_OF(obj), idRespond_to_missing)) {
01622             VALUE args[2];
01623             args[0] = ID2SYM(rb_to_id(mid));
01624             args[1] = priv;
01625             return rb_funcall2(obj, idRespond_to_missing, 2, args);
01626         }
01627         return Qfalse;
01628     }
01629     if (basic_obj_respond_to(obj, id, !RTEST(priv)))
01630         return Qtrue;
01631     return Qfalse;
01632 }
01633 
01634 /*
01635  *  call-seq:
01636  *     obj.respond_to_missing?(symbol, include_all) -> true or false
01637  *
01638  *  DO NOT USE THIS DIRECTLY.
01639  *
01640  *  Hook method to return whether the _obj_ can respond to _id_ method
01641  *  or not.
01642  *
01643  *  See #respond_to?.
01644  */
01645 static VALUE
01646 obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
01647 {
01648     return Qfalse;
01649 }
01650 
01651 void
01652 Init_eval_method(void)
01653 {
01654 #undef rb_intern
01655 #define rb_intern(str) rb_intern_const(str)
01656 
01657     rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
01658     rb_define_method(rb_mKernel, "respond_to_missing?", obj_respond_to_missing, 2);
01659 
01660     rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
01661     rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
01662     rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
01663     rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
01664     rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
01665     rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
01666     rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
01667 
01668     rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
01669     rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
01670     rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
01671     rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
01672     rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
01673     rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
01674 
01675     rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
01676                              "public", top_public, -1);
01677     rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
01678                              "private", top_private, -1);
01679 
01680     object_id = rb_intern("object_id");
01681     added = rb_intern("method_added");
01682     singleton_added = rb_intern("singleton_method_added");
01683     removed = rb_intern("method_removed");
01684     singleton_removed = rb_intern("singleton_method_removed");
01685     undefined = rb_intern("method_undefined");
01686     singleton_undefined = rb_intern("singleton_method_undefined");
01687     attached = rb_intern("__attached__");
01688 
01689     {
01690 #define REPLICATE_METHOD(klass, id, noex) \
01691         rb_method_entry_set((klass), (id), \
01692                             rb_method_entry((klass), (id), 0), \
01693                             (rb_method_flag_t)(noex | NOEX_BASIC | NOEX_NOREDEF))
01694         REPLICATE_METHOD(rb_eException, idMethodMissing, NOEX_PRIVATE);
01695         REPLICATE_METHOD(rb_eException, idRespond_to, NOEX_PUBLIC);
01696         REPLICATE_METHOD(rb_eException, idRespond_to_missing, NOEX_PUBLIC);
01697     }
01698 }
01699