• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

vm_method.c

Go to the documentation of this file.
00001 /*
00002  * This file is included by vm.h
00003  */
00004 
00005 #define CACHE_SIZE 0x800
00006 #define CACHE_MASK 0x7ff
00007 #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
00008 
00009 static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me);
00010 
00011 static ID object_id, respond_to_missing;
00012 static ID removed, singleton_removed, undefined, singleton_undefined;
00013 static ID added, singleton_added, attached;
00014 
00015 struct cache_entry {            /* method hash table. */
00016     ID mid;                     /* method's id */
00017     VALUE klass;                /* receiver's class */
00018     rb_method_entry_t *me;
00019 };
00020 
00021 static struct cache_entry cache[CACHE_SIZE];
00022 #define ruby_running (GET_VM()->running)
00023 /* int ruby_running = 0; */
00024 
00025 void
00026 rb_clear_cache(void)
00027 {
00028     struct cache_entry *ent, *end;
00029 
00030     rb_vm_change_state();
00031 
00032     if (!ruby_running)
00033         return;
00034     ent = cache;
00035     end = ent + CACHE_SIZE;
00036     while (ent < end) {
00037         ent->me = 0;
00038         ent->mid = 0;
00039         ent++;
00040     }
00041 }
00042 
00043 static void
00044 rb_clear_cache_for_undef(VALUE klass, ID id)
00045 {
00046     struct cache_entry *ent, *end;
00047 
00048     rb_vm_change_state();
00049 
00050     if (!ruby_running)
00051         return;
00052     ent = cache;
00053     end = ent + CACHE_SIZE;
00054     while (ent < end) {
00055         if ((ent->me && ent->me->klass == klass) && ent->mid == id) {
00056             ent->me = 0;
00057             ent->mid = 0;
00058         }
00059         ent++;
00060     }
00061 }
00062 
00063 static void
00064 rb_clear_cache_by_id(ID id)
00065 {
00066     struct cache_entry *ent, *end;
00067 
00068     rb_vm_change_state();
00069 
00070     if (!ruby_running)
00071         return;
00072     ent = cache;
00073     end = ent + CACHE_SIZE;
00074     while (ent < end) {
00075         if (ent->mid == id) {
00076             ent->me = 0;
00077             ent->mid = 0;
00078         }
00079         ent++;
00080     }
00081 }
00082 
00083 void
00084 rb_clear_cache_by_class(VALUE klass)
00085 {
00086     struct cache_entry *ent, *end;
00087 
00088     rb_vm_change_state();
00089 
00090     if (!ruby_running)
00091         return;
00092     ent = cache;
00093     end = ent + CACHE_SIZE;
00094     while (ent < end) {
00095         if (ent->klass == klass || (ent->me && ent->me->klass == klass)) {
00096             ent->me = 0;
00097             ent->mid = 0;
00098         }
00099         ent++;
00100     }
00101 }
00102 
00103 VALUE
00104 rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
00105 {
00106     rb_notimplement();
00107 }
00108 
00109 static void
00110 rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex)
00111 {
00112     rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex);
00113 }
00114 
00115 void
00116 rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex)
00117 {
00118     if (func != rb_f_notimplement) {
00119         rb_method_cfunc_t opt;
00120         opt.func = func;
00121         opt.argc = argc;
00122         rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, noex);
00123     }
00124     else {
00125         rb_define_notimplement_method_id(klass, mid, noex);
00126     }
00127 }
00128 
00129 static void
00130 rb_unlink_method_entry(rb_method_entry_t *me)
00131 {
00132     struct unlinked_method_entry_list_entry *ume = ALLOC(struct unlinked_method_entry_list_entry);
00133     ume->me = me;
00134     ume->next = GET_VM()->unlinked_method_entry_list;
00135     GET_VM()->unlinked_method_entry_list = ume;
00136 }
00137 
00138 void
00139 rb_sweep_method_entry(void *pvm)
00140 {
00141     rb_vm_t *vm = pvm;
00142     struct unlinked_method_entry_list_entry *ume = vm->unlinked_method_entry_list, *prev_ume = 0, *curr_ume;
00143 
00144     while (ume) {
00145         if (ume->me->mark) {
00146             ume->me->mark = 0;
00147             prev_ume = ume;
00148             ume = ume->next;
00149         }
00150         else {
00151             rb_free_method_entry(ume->me);
00152 
00153             if (prev_ume == 0) {
00154                 vm->unlinked_method_entry_list = ume->next;
00155             }
00156             else {
00157                 prev_ume->next = ume->next;
00158             }
00159 
00160             curr_ume = ume;
00161             ume = ume->next;
00162             xfree(curr_ume);
00163         }
00164     }
00165 }
00166 
00167 void
00168 rb_free_method_entry(rb_method_entry_t *me)
00169 {
00170     rb_method_definition_t *def = me->def;
00171 
00172     if (def) {
00173         if (def->alias_count == 0) {
00174             xfree(def);
00175         }
00176         else if (def->alias_count > 0) {
00177             def->alias_count--;
00178         }
00179         me->def = 0;
00180     }
00181     xfree(me);
00182 }
00183 
00184 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
00185 
00186 static rb_method_entry_t *
00187 rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
00188                      rb_method_definition_t *def, rb_method_flag_t noex)
00189 {
00190     rb_method_entry_t *me;
00191     st_table *mtbl;
00192     st_data_t data;
00193 
00194     if (NIL_P(klass)) {
00195         klass = rb_cObject;
00196     }
00197     if (rb_safe_level() >= 4 &&
00198         (klass == rb_cObject || !OBJ_UNTRUSTED(klass))) {
00199         rb_raise(rb_eSecurityError, "Insecure: can't define method");
00200     }
00201     if (!FL_TEST(klass, FL_SINGLETON) &&
00202         type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
00203         type != VM_METHOD_TYPE_ZSUPER &&
00204         (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
00205         noex = NOEX_PRIVATE | noex;
00206     }
00207     else if (FL_TEST(klass, FL_SINGLETON) &&
00208              type == VM_METHOD_TYPE_CFUNC &&
00209              mid == rb_intern("allocate")) {
00210         rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()",
00211                 rb_class2name(rb_ivar_get(klass, attached)));
00212         mid = ID_ALLOCATOR;
00213     }
00214     if (OBJ_FROZEN(klass)) {
00215         rb_error_frozen("class/module");
00216     }
00217 
00218     mtbl = RCLASS_M_TBL(klass);
00219 
00220     /* check re-definition */
00221     if (st_lookup(mtbl, mid, &data)) {
00222         rb_method_entry_t *old_me = (rb_method_entry_t *)data;
00223         rb_method_definition_t *old_def = old_me->def;
00224 
00225         if (rb_method_definition_eq(old_def, def)) return old_me;
00226         rb_vm_check_redefinition_opt_method(old_me);
00227 
00228         if (RTEST(ruby_verbose) &&
00229             type != VM_METHOD_TYPE_UNDEF &&
00230             old_def->alias_count == 0 &&
00231             old_def->type != VM_METHOD_TYPE_UNDEF &&
00232             old_def->type != VM_METHOD_TYPE_ZSUPER) {
00233             extern rb_iseq_t *rb_proc_get_iseq(VALUE proc, int *is_proc);
00234             rb_iseq_t *iseq = 0;
00235 
00236             rb_warning("method redefined; discarding old %s", rb_id2name(mid));
00237             switch (old_def->type) {
00238               case VM_METHOD_TYPE_ISEQ:
00239                 iseq = old_def->body.iseq;
00240                 break;
00241               case VM_METHOD_TYPE_BMETHOD:
00242                 iseq = rb_proc_get_iseq(old_def->body.proc, 0);
00243                 break;
00244               default:
00245                 break;
00246             }
00247             if (iseq && !NIL_P(iseq->filename)) {
00248                 int line = iseq->insn_info_table ? rb_iseq_first_lineno(iseq) : 0;
00249                 rb_compile_warning(RSTRING_PTR(iseq->filename), line,
00250                                    "previous definition of %s was here",
00251                                    rb_id2name(old_def->original_id));
00252             }
00253         }
00254 
00255         rb_unlink_method_entry(old_me);
00256     }
00257 
00258     me = ALLOC(rb_method_entry_t);
00259 
00260     rb_clear_cache_by_id(mid);
00261 
00262     me->flag = NOEX_WITH_SAFE(noex);
00263     me->mark = 0;
00264     me->called_id = mid;
00265     me->klass = klass;
00266     me->def = def;
00267     if (def) def->alias_count++;
00268 
00269     /* check mid */
00270     if (klass == rb_cObject && mid == idInitialize) {
00271         rb_warn("redefining Object#initialize may cause infinite loop");
00272     }
00273     /* check mid */
00274     if (mid == object_id || mid == id__send__) {
00275         if (type == VM_METHOD_TYPE_ISEQ) {
00276             rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid));
00277         }
00278     }
00279 
00280     st_insert(mtbl, mid, (st_data_t) me);
00281 
00282     return me;
00283 }
00284 
00285 #define CALL_METHOD_HOOK(klass, hook, mid) do {         \
00286         const VALUE arg = ID2SYM(mid);                  \
00287         VALUE recv_class = klass;                       \
00288         ID hook_id = hook;                              \
00289         if (FL_TEST(klass, FL_SINGLETON)) {             \
00290             recv_class = rb_ivar_get(klass, attached);  \
00291             hook_id = singleton_##hook;                 \
00292         }                                               \
00293         rb_funcall2(recv_class, hook_id, 1, &arg);      \
00294     } while (0)
00295 
00296 static void
00297 method_added(VALUE klass, ID mid)
00298 {
00299     if (mid != ID_ALLOCATOR && ruby_running) {
00300         CALL_METHOD_HOOK(klass, added, mid);
00301     }
00302 }
00303 
00304 rb_method_entry_t *
00305 rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
00306 {
00307     rb_thread_t *th;
00308     rb_control_frame_t *cfp;
00309     int line;
00310     rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex);
00311     rb_method_definition_t *def = ALLOC(rb_method_definition_t);
00312     me->def = def;
00313     def->type = type;
00314     def->original_id = mid;
00315     def->alias_count = 0;
00316     switch (type) {
00317       case VM_METHOD_TYPE_ISEQ:
00318         def->body.iseq = (rb_iseq_t *)opts;
00319         break;
00320       case VM_METHOD_TYPE_CFUNC:
00321         def->body.cfunc = *(rb_method_cfunc_t *)opts;
00322         break;
00323       case VM_METHOD_TYPE_ATTRSET:
00324       case VM_METHOD_TYPE_IVAR:
00325         def->body.attr.id = (ID)opts;
00326         def->body.attr.location = Qfalse;
00327         th = GET_THREAD();
00328         cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
00329         if (cfp && (line = rb_vm_get_sourceline(cfp))) {
00330             VALUE location = rb_ary_new3(2, cfp->iseq->filename, INT2FIX(line));
00331             def->body.attr.location = rb_ary_freeze(location);
00332         }
00333         break;
00334       case VM_METHOD_TYPE_BMETHOD:
00335         def->body.proc = (VALUE)opts;
00336         break;
00337       case VM_METHOD_TYPE_NOTIMPLEMENTED:
00338         def->body.cfunc.func = rb_f_notimplement;
00339         def->body.cfunc.argc = -1;
00340         break;
00341       case VM_METHOD_TYPE_OPTIMIZED:
00342         def->body.optimize_type = (enum method_optimized_type)opts;
00343         break;
00344       case VM_METHOD_TYPE_ZSUPER:
00345       case VM_METHOD_TYPE_UNDEF:
00346         break;
00347       default:
00348         rb_bug("rb_add_method: unsupported method type (%d)\n", type);
00349     }
00350     method_added(klass, mid);
00351     return me;
00352 }
00353 
00354 rb_method_entry_t *
00355 rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_flag_t noex)
00356 {
00357     rb_method_type_t type = me->def ? me->def->type : VM_METHOD_TYPE_UNDEF;
00358     rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex);
00359     method_added(klass, mid);
00360     return newme;
00361 }
00362 
00363 void
00364 rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
00365 {
00366     Check_Type(klass, T_CLASS);
00367     rb_add_method_cfunc(rb_singleton_class(klass), ID_ALLOCATOR,
00368                         func, 0, NOEX_PRIVATE);
00369 }
00370 
00371 void
00372 rb_undef_alloc_func(VALUE klass)
00373 {
00374     Check_Type(klass, T_CLASS);
00375     rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, VM_METHOD_TYPE_UNDEF, 0, NOEX_UNDEF);
00376 }
00377 
00378 rb_alloc_func_t
00379 rb_get_alloc_func(VALUE klass)
00380 {
00381     rb_method_entry_t *me;
00382     Check_Type(klass, T_CLASS);
00383     me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR);
00384 
00385     if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
00386         return (rb_alloc_func_t)me->def->body.cfunc.func;
00387     }
00388     else {
00389         return 0;
00390     }
00391 }
00392 
00393 static rb_method_entry_t*
00394 search_method(VALUE klass, ID id)
00395 {
00396     st_data_t body;
00397     if (!klass) {
00398         return 0;
00399     }
00400 
00401     while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
00402         klass = RCLASS_SUPER(klass);
00403         if (!klass) {
00404             return 0;
00405         }
00406     }
00407 
00408     return (rb_method_entry_t *)body;
00409 }
00410 
00411 /*
00412  * search method entry without the method cache.
00413  *
00414  * if you need method entry with method cache (normal case), use
00415  * rb_method_entry() simply.
00416  */
00417 rb_method_entry_t *
00418 rb_method_entry_get_without_cache(VALUE klass, ID id)
00419 {
00420     rb_method_entry_t *me = search_method(klass, id);
00421 
00422     if (ruby_running) {
00423         struct cache_entry *ent;
00424         ent = cache + EXPR1(klass, id);
00425         ent->klass = klass;
00426 
00427         if (UNDEFINED_METHOD_ENTRY_P(me)) {
00428             ent->mid = id;
00429             ent->me = 0;
00430             me = 0;
00431         }
00432         else {
00433             ent->mid = id;
00434             ent->me = me;
00435         }
00436     }
00437 
00438     return me;
00439 }
00440 
00441 rb_method_entry_t *
00442 rb_method_entry(VALUE klass, ID id)
00443 {
00444     struct cache_entry *ent;
00445 
00446     ent = cache + EXPR1(klass, id);
00447     if (ent->mid == id && ent->klass == klass) {
00448         return ent->me;
00449     }
00450 
00451     return rb_method_entry_get_without_cache(klass, id);
00452 }
00453 
00454 static void
00455 remove_method(VALUE klass, ID mid)
00456 {
00457     st_data_t data;
00458     rb_method_entry_t *me = 0;
00459 
00460     if (klass == rb_cObject) {
00461         rb_secure(4);
00462     }
00463     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
00464         rb_raise(rb_eSecurityError, "Insecure: can't remove method");
00465     }
00466     if (OBJ_FROZEN(klass))
00467         rb_error_frozen("class/module");
00468     if (mid == object_id || mid == id__send__ || mid == idInitialize) {
00469         rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
00470     }
00471 
00472     if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
00473         !(me = (rb_method_entry_t *)data) ||
00474         (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
00475         rb_name_error(mid, "method `%s' not defined in %s",
00476                       rb_id2name(mid), rb_class2name(klass));
00477     }
00478     st_delete(RCLASS_M_TBL(klass), &mid, &data);
00479 
00480     rb_vm_check_redefinition_opt_method(me);
00481     rb_clear_cache_for_undef(klass, mid);
00482     rb_unlink_method_entry(me);
00483 
00484     CALL_METHOD_HOOK(klass, removed, mid);
00485 }
00486 
00487 void
00488 rb_remove_method_id(VALUE klass, ID mid)
00489 {
00490     remove_method(klass, mid);
00491 }
00492 
00493 void
00494 rb_remove_method(VALUE klass, const char *name)
00495 {
00496     remove_method(klass, rb_intern(name));
00497 }
00498 
00499 /*
00500  *  call-seq:
00501  *     remove_method(symbol)   -> self
00502  *
00503  *  Removes the method identified by _symbol_ from the current
00504  *  class. For an example, see <code>Module.undef_method</code>.
00505  */
00506 
00507 static VALUE
00508 rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
00509 {
00510     int i;
00511 
00512     for (i = 0; i < argc; i++) {
00513         remove_method(mod, rb_to_id(argv[i]));
00514     }
00515     return mod;
00516 }
00517 
00518 #undef rb_disable_super
00519 #undef rb_enable_super
00520 
00521 void
00522 rb_disable_super(VALUE klass, const char *name)
00523 {
00524     /* obsolete - no use */
00525 }
00526 
00527 void
00528 rb_enable_super(VALUE klass, const char *name)
00529 {
00530     rb_warning("rb_enable_super() is obsolete");
00531 }
00532 
00533 static void
00534 rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
00535 {
00536     rb_method_entry_t *me;
00537 
00538     if (klass == rb_cObject) {
00539         rb_secure(4);
00540     }
00541 
00542     me = search_method(klass, name);
00543     if (!me && TYPE(klass) == T_MODULE) {
00544         me = search_method(rb_cObject, name);
00545     }
00546 
00547     if (UNDEFINED_METHOD_ENTRY_P(me)) {
00548         rb_print_undef(klass, name, 0);
00549     }
00550 
00551     if (me->flag != noex) {
00552         rb_vm_check_redefinition_opt_method(me);
00553 
00554         if (klass == me->klass) {
00555             me->flag = noex;
00556         }
00557         else {
00558             rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
00559         }
00560     }
00561 }
00562 
00563 int
00564 rb_method_boundp(VALUE klass, ID id, int ex)
00565 {
00566     rb_method_entry_t *me = rb_method_entry(klass, id);
00567 
00568     if (me != 0) {
00569         if ((ex & ~NOEX_RESPONDS) && (me->flag & NOEX_PRIVATE)) {
00570             return FALSE;
00571         }
00572         if (!me->def) return 0;
00573         if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
00574             if (ex & NOEX_RESPONDS) return 2;
00575             return 0;
00576         }
00577         return 1;
00578     }
00579     return 0;
00580 }
00581 
00582 void
00583 rb_attr(VALUE klass, ID id, int read, int write, int ex)
00584 {
00585     const char *name;
00586     ID attriv;
00587     VALUE aname;
00588     rb_method_flag_t noex;
00589 
00590     if (!ex) {
00591         noex = NOEX_PUBLIC;
00592     }
00593     else {
00594         if (SCOPE_TEST(NOEX_PRIVATE)) {
00595             noex = NOEX_PRIVATE;
00596             rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
00597                        "attribute accessor as module_function" :
00598                        "private attribute?");
00599         }
00600         else if (SCOPE_TEST(NOEX_PROTECTED)) {
00601             noex = NOEX_PROTECTED;
00602         }
00603         else {
00604             noex = NOEX_PUBLIC;
00605         }
00606     }
00607 
00608     if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
00609         rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
00610     }
00611     name = rb_id2name(id);
00612     if (!name) {
00613         rb_raise(rb_eArgError, "argument needs to be symbol or string");
00614     }
00615     aname = rb_sprintf("@%s", name);
00616     rb_enc_copy(aname, rb_id2str(id));
00617     attriv = rb_intern_str(aname);
00618     if (read) {
00619         rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, noex);
00620     }
00621     if (write) {
00622         rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, noex);
00623     }
00624 }
00625 
00626 void
00627 rb_undef(VALUE klass, ID id)
00628 {
00629     rb_method_entry_t *me;
00630 
00631     if (NIL_P(klass)) {
00632         rb_raise(rb_eTypeError, "no class to undef method");
00633     }
00634     if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
00635         rb_secure(4);
00636     }
00637     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
00638         rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
00639     }
00640     rb_frozen_class_p(klass);
00641     if (id == object_id || id == id__send__ || id == idInitialize) {
00642         rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
00643     }
00644 
00645     me = search_method(klass, id);
00646 
00647     if (UNDEFINED_METHOD_ENTRY_P(me)) {
00648         const char *s0 = " class";
00649         VALUE c = klass;
00650 
00651         if (FL_TEST(c, FL_SINGLETON)) {
00652             VALUE obj = rb_ivar_get(klass, attached);
00653 
00654             switch (TYPE(obj)) {
00655               case T_MODULE:
00656               case T_CLASS:
00657                 c = obj;
00658                 s0 = "";
00659             }
00660         }
00661         else if (TYPE(c) == T_MODULE) {
00662             s0 = " module";
00663         }
00664         rb_name_error(id, "undefined method `%s' for%s `%s'",
00665                       rb_id2name(id), s0, rb_class2name(c));
00666     }
00667 
00668     rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
00669 
00670     CALL_METHOD_HOOK(klass, undefined, id);
00671 }
00672 
00673 /*
00674  *  call-seq:
00675  *     undef_method(symbol)    -> self
00676  *
00677  *  Prevents the current class from responding to calls to the named
00678  *  method. Contrast this with <code>remove_method</code>, which deletes
00679  *  the method from the particular class; Ruby will still search
00680  *  superclasses and mixed-in modules for a possible receiver.
00681  *
00682  *     class Parent
00683  *       def hello
00684  *         puts "In parent"
00685  *       end
00686  *     end
00687  *     class Child < Parent
00688  *       def hello
00689  *         puts "In child"
00690  *       end
00691  *     end
00692  *
00693  *
00694  *     c = Child.new
00695  *     c.hello
00696  *
00697  *
00698  *     class Child
00699  *       remove_method :hello  # remove from child, still in parent
00700  *     end
00701  *     c.hello
00702  *
00703  *
00704  *     class Child
00705  *       undef_method :hello   # prevent any calls to 'hello'
00706  *     end
00707  *     c.hello
00708  *
00709  *  <em>produces:</em>
00710  *
00711  *     In child
00712  *     In parent
00713  *     prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError)
00714  */
00715 
00716 static VALUE
00717 rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
00718 {
00719     int i;
00720     for (i = 0; i < argc; i++) {
00721         rb_undef(mod, rb_to_id(argv[i]));
00722     }
00723     return mod;
00724 }
00725 
00726 /*
00727  *  call-seq:
00728  *     mod.method_defined?(symbol)    -> true or false
00729  *
00730  *  Returns +true+ if the named method is defined by
00731  *  _mod_ (or its included modules and, if _mod_ is a class,
00732  *  its ancestors). Public and protected methods are matched.
00733  *
00734  *     module A
00735  *       def method1()  end
00736  *     end
00737  *     class B
00738  *       def method2()  end
00739  *     end
00740  *     class C < B
00741  *       include A
00742  *       def method3()  end
00743  *     end
00744  *
00745  *     A.method_defined? :method1    #=> true
00746  *     C.method_defined? "method1"   #=> true
00747  *     C.method_defined? "method2"   #=> true
00748  *     C.method_defined? "method3"   #=> true
00749  *     C.method_defined? "method4"   #=> false
00750  */
00751 
00752 static VALUE
00753 rb_mod_method_defined(VALUE mod, VALUE mid)
00754 {
00755     if (!rb_method_boundp(mod, rb_to_id(mid), 1)) {
00756         return Qfalse;
00757     }
00758     return Qtrue;
00759 
00760 }
00761 
00762 #define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
00763 
00764 static VALUE
00765 check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
00766 {
00767     const rb_method_entry_t *me;
00768     me = rb_method_entry(mod, mid);
00769     if (me) {
00770         if (VISI_CHECK(me->flag, noex))
00771             return Qtrue;
00772     }
00773     return Qfalse;
00774 }
00775 
00776 /*
00777  *  call-seq:
00778  *     mod.public_method_defined?(symbol)   -> true or false
00779  *
00780  *  Returns +true+ if the named public method is defined by
00781  *  _mod_ (or its included modules and, if _mod_ is a class,
00782  *  its ancestors).
00783  *
00784  *     module A
00785  *       def method1()  end
00786  *     end
00787  *     class B
00788  *       protected
00789  *       def method2()  end
00790  *     end
00791  *     class C < B
00792  *       include A
00793  *       def method3()  end
00794  *     end
00795  *
00796  *     A.method_defined? :method1           #=> true
00797  *     C.public_method_defined? "method1"   #=> true
00798  *     C.public_method_defined? "method2"   #=> false
00799  *     C.method_defined? "method2"          #=> true
00800  */
00801 
00802 static VALUE
00803 rb_mod_public_method_defined(VALUE mod, VALUE mid)
00804 {
00805     return check_definition(mod, rb_to_id(mid), NOEX_PUBLIC);
00806 }
00807 
00808 /*
00809  *  call-seq:
00810  *     mod.private_method_defined?(symbol)    -> true or false
00811  *
00812  *  Returns +true+ if the named private method is defined by
00813  *  _ mod_ (or its included modules and, if _mod_ is a class,
00814  *  its ancestors).
00815  *
00816  *     module A
00817  *       def method1()  end
00818  *     end
00819  *     class B
00820  *       private
00821  *       def method2()  end
00822  *     end
00823  *     class C < B
00824  *       include A
00825  *       def method3()  end
00826  *     end
00827  *
00828  *     A.method_defined? :method1            #=> true
00829  *     C.private_method_defined? "method1"   #=> false
00830  *     C.private_method_defined? "method2"   #=> true
00831  *     C.method_defined? "method2"           #=> false
00832  */
00833 
00834 static VALUE
00835 rb_mod_private_method_defined(VALUE mod, VALUE mid)
00836 {
00837     return check_definition(mod, rb_to_id(mid), NOEX_PRIVATE);
00838 }
00839 
00840 /*
00841  *  call-seq:
00842  *     mod.protected_method_defined?(symbol)   -> true or false
00843  *
00844  *  Returns +true+ if the named protected method is defined
00845  *  by _mod_ (or its included modules and, if _mod_ is a
00846  *  class, its ancestors).
00847  *
00848  *     module A
00849  *       def method1()  end
00850  *     end
00851  *     class B
00852  *       protected
00853  *       def method2()  end
00854  *     end
00855  *     class C < B
00856  *       include A
00857  *       def method3()  end
00858  *     end
00859  *
00860  *     A.method_defined? :method1              #=> true
00861  *     C.protected_method_defined? "method1"   #=> false
00862  *     C.protected_method_defined? "method2"   #=> true
00863  *     C.method_defined? "method2"             #=> true
00864  */
00865 
00866 static VALUE
00867 rb_mod_protected_method_defined(VALUE mod, VALUE mid)
00868 {
00869     return check_definition(mod, rb_to_id(mid), NOEX_PROTECTED);
00870 }
00871 
00872 int
00873 rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
00874 {
00875     return rb_method_definition_eq(m1->def, m2->def);
00876 }
00877 
00878 static int
00879 rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
00880 {
00881     if (d1 == d2) return 1;
00882     if (!d1 || !d2) return 0;
00883     if (d1->type != d2->type) {
00884         return 0;
00885     }
00886     switch (d1->type) {
00887       case VM_METHOD_TYPE_ISEQ:
00888         return d1->body.iseq == d2->body.iseq;
00889       case VM_METHOD_TYPE_CFUNC:
00890         return
00891           d1->body.cfunc.func == d2->body.cfunc.func &&
00892           d1->body.cfunc.argc == d2->body.cfunc.argc;
00893       case VM_METHOD_TYPE_ATTRSET:
00894       case VM_METHOD_TYPE_IVAR:
00895         return d1->body.attr.id == d2->body.attr.id;
00896       case VM_METHOD_TYPE_BMETHOD:
00897         return RTEST(rb_equal(d1->body.proc, d2->body.proc));
00898       case VM_METHOD_TYPE_MISSING:
00899         return d1->original_id == d2->original_id;
00900       case VM_METHOD_TYPE_ZSUPER:
00901       case VM_METHOD_TYPE_NOTIMPLEMENTED:
00902       case VM_METHOD_TYPE_UNDEF:
00903         return 1;
00904       case VM_METHOD_TYPE_OPTIMIZED:
00905         return d1->body.optimize_type == d2->body.optimize_type;
00906       default:
00907         rb_bug("rb_method_entry_eq: unsupported method type (%d)\n", d1->type);
00908         return 0;
00909     }
00910 }
00911 
00912 void
00913 rb_alias(VALUE klass, ID name, ID def)
00914 {
00915     VALUE target_klass = klass;
00916     rb_method_entry_t *orig_me;
00917     rb_method_flag_t flag = NOEX_UNDEF;
00918 
00919     if (NIL_P(klass)) {
00920         rb_raise(rb_eTypeError, "no class to make alias");
00921     }
00922 
00923     rb_frozen_class_p(klass);
00924     if (klass == rb_cObject) {
00925         rb_secure(4);
00926     }
00927 
00928   again:
00929     orig_me = search_method(klass, def);
00930 
00931     if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
00932         if ((TYPE(klass) != T_MODULE) ||
00933             (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) {
00934             rb_print_undef(klass, def, 0);
00935         }
00936     }
00937     if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
00938         klass = RCLASS_SUPER(klass);
00939         def = orig_me->def->original_id;
00940         flag = orig_me->flag;
00941         goto again;
00942     }
00943 
00944     if (flag == NOEX_UNDEF) flag = orig_me->flag;
00945     rb_method_entry_set(target_klass, name, orig_me, flag);
00946 }
00947 
00948 /*
00949  *  call-seq:
00950  *     alias_method(new_name, old_name)   -> self
00951  *
00952  *  Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can
00953  *  be used to retain access to methods that are overridden.
00954  *
00955  *     module Mod
00956  *       alias_method :orig_exit, :exit
00957  *       def exit(code=0)
00958  *         puts "Exiting with code #{code}"
00959  *         orig_exit(code)
00960  *       end
00961  *     end
00962  *     include Mod
00963  *     exit(99)
00964  *
00965  *  <em>produces:</em>
00966  *
00967  *     Exiting with code 99
00968  */
00969 
00970 static VALUE
00971 rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
00972 {
00973     rb_alias(mod, rb_to_id(newname), rb_to_id(oldname));
00974     return mod;
00975 }
00976 
00977 static void
00978 secure_visibility(VALUE self)
00979 {
00980     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(self)) {
00981         rb_raise(rb_eSecurityError,
00982                  "Insecure: can't change method visibility");
00983     }
00984 }
00985 
00986 static void
00987 set_method_visibility(VALUE self, int argc, VALUE *argv, rb_method_flag_t ex)
00988 {
00989     int i;
00990     secure_visibility(self);
00991     for (i = 0; i < argc; i++) {
00992         rb_export_method(self, rb_to_id(argv[i]), ex);
00993     }
00994     rb_clear_cache_by_class(self);
00995 }
00996 
00997 /*
00998  *  call-seq:
00999  *     public                 -> self
01000  *     public(symbol, ...)    -> self
01001  *
01002  *  With no arguments, sets the default visibility for subsequently
01003  *  defined methods to public. With arguments, sets the named methods to
01004  *  have public visibility.
01005  */
01006 
01007 static VALUE
01008 rb_mod_public(int argc, VALUE *argv, VALUE module)
01009 {
01010     secure_visibility(module);
01011     if (argc == 0) {
01012         SCOPE_SET(NOEX_PUBLIC);
01013     }
01014     else {
01015         set_method_visibility(module, argc, argv, NOEX_PUBLIC);
01016     }
01017     return module;
01018 }
01019 
01020 /*
01021  *  call-seq:
01022  *     protected                -> self
01023  *     protected(symbol, ...)   -> self
01024  *
01025  *  With no arguments, sets the default visibility for subsequently
01026  *  defined methods to protected. With arguments, sets the named methods
01027  *  to have protected visibility.
01028  */
01029 
01030 static VALUE
01031 rb_mod_protected(int argc, VALUE *argv, VALUE module)
01032 {
01033     secure_visibility(module);
01034     if (argc == 0) {
01035         SCOPE_SET(NOEX_PROTECTED);
01036     }
01037     else {
01038         set_method_visibility(module, argc, argv, NOEX_PROTECTED);
01039     }
01040     return module;
01041 }
01042 
01043 /*
01044  *  call-seq:
01045  *     private                 -> self
01046  *     private(symbol, ...)    -> self
01047  *
01048  *  With no arguments, sets the default visibility for subsequently
01049  *  defined methods to private. With arguments, sets the named methods
01050  *  to have private visibility.
01051  *
01052  *     module Mod
01053  *       def a()  end
01054  *       def b()  end
01055  *       private
01056  *       def c()  end
01057  *       private :a
01058  *     end
01059  *     Mod.private_instance_methods   #=> [:a, :c]
01060  */
01061 
01062 static VALUE
01063 rb_mod_private(int argc, VALUE *argv, VALUE module)
01064 {
01065     secure_visibility(module);
01066     if (argc == 0) {
01067         SCOPE_SET(NOEX_PRIVATE);
01068     }
01069     else {
01070         set_method_visibility(module, argc, argv, NOEX_PRIVATE);
01071     }
01072     return module;
01073 }
01074 
01075 /*
01076  *  call-seq:
01077  *     mod.public_class_method(symbol, ...)    -> mod
01078  *
01079  *  Makes a list of existing class methods public.
01080  */
01081 
01082 static VALUE
01083 rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
01084 {
01085     set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
01086     return obj;
01087 }
01088 
01089 /*
01090  *  call-seq:
01091  *     mod.private_class_method(symbol, ...)   -> mod
01092  *
01093  *  Makes existing class methods private. Often used to hide the default
01094  *  constructor <code>new</code>.
01095  *
01096  *     class SimpleSingleton  # Not thread safe
01097  *       private_class_method :new
01098  *       def SimpleSingleton.create(*args, &block)
01099  *         @me = new(*args, &block) if ! @me
01100  *         @me
01101  *       end
01102  *     end
01103  */
01104 
01105 static VALUE
01106 rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
01107 {
01108     set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
01109     return obj;
01110 }
01111 
01112 /*
01113  *  call-seq:
01114  *     public
01115  *     public(symbol, ...)
01116  *
01117  *  With no arguments, sets the default visibility for subsequently
01118  *  defined methods to public. With arguments, sets the named methods to
01119  *  have public visibility.
01120  */
01121 
01122 static VALUE
01123 top_public(int argc, VALUE *argv)
01124 {
01125     return rb_mod_public(argc, argv, rb_cObject);
01126 }
01127 
01128 static VALUE
01129 top_private(int argc, VALUE *argv)
01130 {
01131     return rb_mod_private(argc, argv, rb_cObject);
01132 }
01133 
01134 /*
01135  *  call-seq:
01136  *     module_function(symbol, ...)    -> self
01137  *
01138  *  Creates module functions for the named methods. These functions may
01139  *  be called with the module as a receiver, and also become available
01140  *  as instance methods to classes that mix in the module. Module
01141  *  functions are copies of the original, and so may be changed
01142  *  independently. The instance-method versions are made private. If
01143  *  used with no arguments, subsequently defined methods become module
01144  *  functions.
01145  *
01146  *     module Mod
01147  *       def one
01148  *         "This is one"
01149  *       end
01150  *       module_function :one
01151  *     end
01152  *     class Cls
01153  *       include Mod
01154  *       def callOne
01155  *         one
01156  *       end
01157  *     end
01158  *     Mod.one     #=> "This is one"
01159  *     c = Cls.new
01160  *     c.callOne   #=> "This is one"
01161  *     module Mod
01162  *       def one
01163  *         "This is the new one"
01164  *       end
01165  *     end
01166  *     Mod.one     #=> "This is one"
01167  *     c.callOne   #=> "This is the new one"
01168  */
01169 
01170 static VALUE
01171 rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
01172 {
01173     int i;
01174     ID id;
01175     const rb_method_entry_t *me;
01176 
01177     if (TYPE(module) != T_MODULE) {
01178         rb_raise(rb_eTypeError, "module_function must be called for modules");
01179     }
01180 
01181     secure_visibility(module);
01182     if (argc == 0) {
01183         SCOPE_SET(NOEX_MODFUNC);
01184         return module;
01185     }
01186 
01187     set_method_visibility(module, argc, argv, NOEX_PRIVATE);
01188 
01189     for (i = 0; i < argc; i++) {
01190         VALUE m = module;
01191 
01192         id = rb_to_id(argv[i]);
01193         for (;;) {
01194             me = search_method(m, id);
01195             if (me == 0) {
01196                 me = search_method(rb_cObject, id);
01197             }
01198             if (UNDEFINED_METHOD_ENTRY_P(me)) {
01199                 rb_print_undef(module, id, 0);
01200             }
01201             if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
01202                 break; /* normal case: need not to follow 'super' link */
01203             }
01204             m = RCLASS_SUPER(m);
01205             if (!m)
01206                 break;
01207         }
01208         rb_method_entry_set(rb_singleton_class(module), id, me, NOEX_PUBLIC);
01209     }
01210     return module;
01211 }
01212 
01213 int
01214 rb_method_basic_definition_p(VALUE klass, ID id)
01215 {
01216     const rb_method_entry_t *me = rb_method_entry(klass, id);
01217     if (me && (me->flag & NOEX_BASIC))
01218         return 1;
01219     return 0;
01220 }
01221 
01222 static inline int
01223 basic_obj_respond_to(VALUE obj, ID id, int pub)
01224 {
01225     VALUE klass = CLASS_OF(obj);
01226 
01227     switch (rb_method_boundp(klass, id, pub|NOEX_RESPONDS)) {
01228       case 2:
01229         return FALSE;
01230       case 0:
01231         return RTEST(rb_funcall(obj, respond_to_missing, 2, ID2SYM(id), pub ? Qfalse : Qtrue));
01232       default:
01233         return TRUE;
01234     }
01235 }
01236 
01237 int
01238 rb_obj_respond_to(VALUE obj, ID id, int priv)
01239 {
01240     VALUE klass = CLASS_OF(obj);
01241 
01242     if (rb_method_basic_definition_p(klass, idRespond_to)) {
01243         return basic_obj_respond_to(obj, id, !RTEST(priv));
01244     }
01245     else {
01246         return RTEST(rb_funcall(obj, idRespond_to, priv ? 2 : 1, ID2SYM(id), Qtrue));
01247     }
01248 }
01249 
01250 int
01251 rb_respond_to(VALUE obj, ID id)
01252 {
01253     return rb_obj_respond_to(obj, id, FALSE);
01254 }
01255 
01256 
01257 /*
01258  *  call-seq:
01259  *     obj.respond_to?(symbol, include_private=false) -> true or false
01260  *
01261  *  Returns +true+ if _obj_ responds to the given
01262  *  method. Private methods are included in the search only if the
01263  *  optional second parameter evaluates to +true+.
01264  *
01265  *  If the method is not implemented,
01266  *  as Process.fork on Windows, File.lchmod on GNU/Linux, etc.,
01267  *  false is returned.
01268  *
01269  *  If the method is not defined, <code>respond_to_missing?</code>
01270  *  method is called and the result is returned.
01271  */
01272 
01273 static VALUE
01274 obj_respond_to(int argc, VALUE *argv, VALUE obj)
01275 {
01276     VALUE mid, priv;
01277     ID id;
01278 
01279     rb_scan_args(argc, argv, "11", &mid, &priv);
01280     id = rb_to_id(mid);
01281     if (basic_obj_respond_to(obj, id, !RTEST(priv)))
01282         return Qtrue;
01283     return Qfalse;
01284 }
01285 
01286 /*
01287  *  call-seq:
01288  *     obj.respond_to_missing?(symbol, include_private) -> true or false
01289  *
01290  *  Hook method to return whether the _obj_ can respond to _id_ method
01291  *  or not.
01292  *
01293  *  See #respond_to?.
01294  */
01295 static VALUE
01296 obj_respond_to_missing(VALUE obj, VALUE priv)
01297 {
01298     return Qfalse;
01299 }
01300 
01301 void
01302 Init_eval_method(void)
01303 {
01304 #undef rb_intern
01305 #define rb_intern(str) rb_intern_const(str)
01306 
01307     rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
01308     rb_define_method(rb_mKernel, "respond_to_missing?", obj_respond_to_missing, 2);
01309 
01310     rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
01311     rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
01312     rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
01313     rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
01314     rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
01315     rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
01316     rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
01317 
01318     rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
01319     rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
01320     rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
01321     rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
01322     rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
01323     rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
01324 
01325     rb_define_singleton_method(rb_vm_top_self(), "public", top_public, -1);
01326     rb_define_singleton_method(rb_vm_top_self(), "private", top_private, -1);
01327 
01328     object_id = rb_intern("object_id");
01329     added = rb_intern("method_added");
01330     singleton_added = rb_intern("singleton_method_added");
01331     removed = rb_intern("method_removed");
01332     singleton_removed = rb_intern("singleton_method_removed");
01333     undefined = rb_intern("method_undefined");
01334     singleton_undefined = rb_intern("singleton_method_undefined");
01335     attached = rb_intern("__attached__");
01336     respond_to_missing = rb_intern("respond_to_missing?");
01337 }
01338 
01339 

Generated on Sat Jul 7 2012 15:29:25 for Ruby by  doxygen 1.7.1