vm_method.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7